我希望有一个变量(实际上是函数参数,但我简化了问题),它可以包含Reaction组件,该组件必须在其属性中包含aNumber: number
。
我未成功的尝试是:
function MyComp(props: { aNumber: number, aString: string }) {
return <>{props.aNumber} {props.aString}</>;
}
let f2: FunctionComponent<{ aNumber: number }> = MyComp;
给我错误:
Type '(props: { aNumber: number; aString: string; }) => Element' is not assignable to type 'FunctionComponent<{ aNumber: number; }>'.
Types of parameters 'props' and 'props' are incompatible.
Property 'aString' is missing in type 'PropsWithChildren<{ aNumber: number; }>' but required in type '{ aNumber: number; aString: string; }'.ts(2322)
FunctionComponent
在Reaction中定义为:
interface FunctionComponent<P = {}> {
(props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;
propTypes?: WeakValidationMap<P>;
contextTypes?: ValidationMap<any>;
defaultProps?: Partial<P>;
displayName?: string;
}
我不明白这个错误。如果我定义了一个var w/a约束aNumber
,并且为它分配了一个更丰富的元素=>;,为什么它不满意呢?为什么它会抱怨这些更丰富的属性?
当然,以下是可行的:
let f1: FunctionComponent<any> = MyComp;
通常,当我在TS中尝试高级类型构造时,在经历了许多头痛之后,我终于让它工作了。这一次它似乎不是很高级,但我没能弄明白。
提前表示感谢。
推荐答案
问题是,反应组件是函数,而函数是反向变量,这意味着如果需要具有T
类型参数的函数,则它可以满足于比T
更宽类型的函数,但不能满足较窄类型的函数。这与纯对象相反,后者是co变体,即将接受较窄的类型,但不接受较宽的类型。
您可以在没有任何反应代码的情况下看到相同的结果
function MyFunc(props:{a: number, b: string}){return}
let func2: (props:{a:number})=>void = MyFunc
// ^-- error because MyFunc is narrower than typeof func2
从调用您的函数/Reaction组件的消费者的角度来看,这是一种直观的方式。在他们期望调用typeof f2
的函数的情况下,他们预计只需要传递aNumber
的道具,但是通过将更窄的函数分配给f2,他们现在还需要传递aString
,这是他们没有预料到的。
出于可以理解的原因,这个问题经常出现在我们的反应中。假设您有一个<Button>
组件和一个<FancyButton>
组件,前者需要一个道具,后者需要多个道具。人们不禁会想,如果我需要一个旧的<Button>
,那么一个<FancyButton>
就可以了。这听起来像是简单的继承。但如果你再想一想,就会发现有一个错误。如果我是一个组件,希望需要插入<Button>
作为我的子级之一,这意味着我只需要向它传递一个道具。如果我现在换入<FancyButton>
,组件现在需要一些我不希望提供道具。
直观的观点是,您不仅仅是显示<Button>
组件--在这种情况下,您可能根本不关心<FancyButton>
具有更多的&q;幻想&q;这一事实。您实际上需要向组件提供输入--道具,因此范围较小的输入将需要您(父组件)提供更多。
当然,相同的逻辑对于所有函数通常都是正确的,但我猜这往往会在Reaction中更频繁地出现,因为我们倾向于将组件视为要显示的对象。
这里有一个关于这个问题的更广泛的答案(一开始很棘手!):Difference between covariant and contravariant positions in Typescript
相关推荐
最新文章