gpt4 book ai didi

reactjs - react 和 typescript : How to extend generic component props?

转载 作者:行者123 更新时间:2023-12-02 16:26:42 32 4
gpt4 key购买 nike

想象一个灵活的组件,它接受一个 React.ComponentType 和它的 props 并渲染它:

type Props<C> = {
component: React.ComponentType<C>;
componentProps: C;
otherProp: string;
};

const MyComponent = <C extends {}>(props: Props<C>) => {
return React.createElement(props.component, props.componentProps);
};

我能否以某种方式让 MyComponent 直接接收动态 props,例如像那样(不工作):

type Props<C> = {
component: React.ComponentType<C>;
otherProp: string;
};

const MyComponent = <C extends {}>(props: Props<C> & C) => {
const { otherProp, component, ...componentProps } = props;
return React.createElement(component, componentProps);
};

错误:

Error:(11, 41) TS2769: No overload matches this call.
The last overload gave the following error.
Argument of type 'Pick<Props<C> & C, Exclude<keyof C, "component" | "otherProp">>' is not assignable to parameter of type 'Attributes & C'.
Type 'Pick<Props<C> & C, Exclude<keyof C, "component" | "otherProp">>' is not assignable to type 'C'.
'Pick<Props<C> & C, Exclude<keyof C, "component" | "otherProp">>' is assignable to the constraint of type 'C', but 'C' could be instantiated with a different subtype of constraint '{}'.

最佳答案

这里我们需要了解一些实用类型以及解构在 TS 中是如何发生的。

type Obj = {
[key: string]: any
}

interface I1 {
a: number
b: number
c: number
}

const i1: I1 = {
a: 1,
b: 1,
c: 1,
}

let {a, ...rest} = i1

interface Obj {
[key: string]: any
}

const i2: Obj & I1 = {
a: 1,
b: 1,
c: 1,
d: 1,
e: 1,
}

let {a: a1, b, c, ...rest2} = i2

function func<T extends Obj>(param: I1 & T) {
const {a, b, c, ...rest} = param
}

在上面的代码中,rest 的推断类型将是 {b: number, c: number}因为对象 i1仅包含三个键,其中一个又名 a筋疲力尽。在rest2的情况下, TS 仍然可以将类型推断为 Obj作为界面中的键 I1筋疲力尽。精疲力竭的意思是它们不是使用 rest 运算符捕获的。

但在函数的情况下,TS 无法进行此类推理。我不知道为什么TS做不到。这可能是由于泛型的限制。

在函数的情况下发生的是 rest 的类型函数内部是Pick<I1 & T, Exclude<keyof T, "a" | "b" | "c">> . Exclude不包括键 a , bc来自通用类型 T .检查排除 here .然后,PickI1 & T 创建一个新类型使用 Exclude 返回的 key .自 T可以是任何类型,即使 T 被限制为 Obj,TS 也无法确定排除后的键,因此无法确定选择的键和新创建的类型.这就是类型变量 rest 的原因在函数中仍然是 Pick<I1 & T, Exclude<keyof T, "a" | "b" | "c">> .

请注意 Pick 返回的类型是 Obj 的子类型

现在问题来了,同样的情况发生在componentProps上。 .推断的类型将为 Pick<Props<C> & C, Exclude<keyof C, "otherProp" | "component">> . TS 将无法缩小范围。查看 React.createElement 的签名

 function createElement<P extends {}>(
type: ComponentType<P> | string,
props?: Attributes & P | null,
...children: ReactNode[]): ReactElement<P>

并调用它

React.createElement(component, componentProps)

P 的推断类型在签名中将是C在第一个参数的代码中,即 component因为它的类型是 React.ComponentType<C> .第二个参数应该是 undefinednullC (忽略 Attributes 截至目前)。但是 componentProps 的类型是Pick<Props<C> & C, Exclude<keyof C, "otherProp" | "component">> , 这绝对可以分配给 {}但不是 C因为它是 {} 的子类型不属于 C . C也是 {} 的子类型但是选择类型和C可能兼容也可能不兼容(这与 - 有一个类 A;B 和 C 派生 A,B 和 C 的对象可分配给 A,但 B 的对象不可归因于 C)相同。这就是错误的原因

        'Pick<Props<C> & C, Exclude<keyof C, "component" | "otherProp">>' is assignable to the constraint of type 'C', but 'C' could be instantiated with a different subtype of constraint '{}'.

由于我们比 TS 编译器更聪明,我们知道它们是兼容的,但 TS 不兼容。所以让 TS 相信我们做的是正确的,我们可以做这样的类型断言

type Props<C> = {
component: React.ComponentType<C>;
otherProp: string;
};

const MyComponent = <C extends {}>(props: Props<C> & C) => {
const { otherProp, component, ...componentProps } = props;
return React.createElement(component, componentProps as unknown as C);
// ------------------------------------------------^^^^^^^^
};

这绝对是一个正确的类型断言,因为我们知道 componentProps 的类型将是 C

希望这能回答您的问题并解决您的问题。

关于reactjs - react 和 typescript : How to extend generic component props?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64305120/

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