gpt4 book ai didi

reactjs - 要求在 props 中至少提供两个属性之一

转载 作者:搜寻专家 更新时间:2023-10-30 21:27:21 24 4
gpt4 key购买 nike

使用 TypeScript,可以创建一个类型,其中至少两个属性是必需的。有(至少)两种方法可以解决这个问题:using union typesa somewhat complexer generic solution .这两种解决方案效果很好。当两个属性均未指定时,我能够创建并获得所需的编译器错误。

但是,当使用 final 类型指定 react 组件中的 props 时,编译器无法找到这两个“必需”属性。这是一个简化的示例:

interface Base {
text?: string;
}
interface WithId extends Base {
id: number;
}
interface WithToken extends Base {
token: string;
}
type Identifiable = WithId | WithToken | (WithId & WithToken);

//OK
const item: Identifiable = {
text: "some text"
id: 4
};
//OK
const item: Identifiable = {
token: "some token"
};
//Error
const item: Identifiable = {
text: "some text"
};

//OK
export class MyComponent extends React.Component<Identifiable, any> {
render() {
//Error (see below)
return <p>{this.props.id}</p>
}
}

尝试访问两个必需的 props 之一时收到的错误(无论在类中的哪个位置)看起来像这样:

Property 'id' does not exist on type '(Readonly<{children?: ReactNode;}> & Readonly<WithId>) | (Readonly<{children?: ReactNode;}> & Readonly<WithToken>) | (Readonly<{children?: ReactNode;}> & Readonly<WithId & WithToken>)'
Property 'id' does not exist on type '(Readonly<{children?: ReactNode;}> & Readonly<WithToken>'.

有没有办法解决这个问题并让编译器理解这些要求?

注意:使用 TypeScript 3.0.1、React 16.4.2,以及迄今为止可用的最新类型。

最佳答案

您不能访问联合体的所有成员不共有的字段。

想到的选项是类型保护或在实际使用它们时使用不同类型的 Prop 。

简单的选项是类型保护,只需使用 in 类型保护检查属性是否存在:

export class MyComponent extends React.Component<Identifiable, any> {
render() {
if ('id' in this.props) {
// Ok
return <p>{this.props.id}</p>
}
}
}

第二个更复杂的解决方案是从 Identifiable 创建一个类型,它是同一个联合体,但是联合体的每个成员都增加了缺失的字段,形成了所有联合体,缺失的字段是可选的并且类型未定义。基本上我们想要获取表单 { id: string } | { token: string } { id: string; token ?:未定义} | { token :字符串; id?:undefined .这将允许我们访问联合的任何字段,同时在 strictNullChecks 下仍然是类型安全的。

这种新类型仍将与您原来的 props 兼容,因此我们只需要这种类型的局部变量并将其分配给类 props。

type UnionToIntersection<U> =
(U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never


type FlattenUnionHelper<T, TAll> = T extends any ? T & Partial<Record<Exclude<keyof TAll, keyof T>, undefined>> : never;
type FlattenUnion<T> = FlattenUnionHelper<T, UnionToIntersection<T>>


export class MyComponent extends React.Component<Identifiable, any> {
render() {
let props: FlattenUnion<Identifiable> = this.props
return <p>{props.id}</p>
}
}

我认为你可以直接使用扁平化版本作为 Prop ,但你应该测试你的所有要求是否得到满足,从我测试的情况来看它工作正常

export class MyComponent extends React.Component<FlattenUnion<Identifiable>, any> { /*...*/}
let f = <MyComponent id={0} />
let f2 = <MyComponent token="" />
let f3 = <MyComponent id={0} token="" />
let f4 = <MyComponent text="" /> // error

关于reactjs - 要求在 props 中至少提供两个属性之一,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51889715/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com