假设我有以下对象:
const arrayOfDifferentComponents: HowDoITypeThis = [
{
component: ComponentOne, // no error, keys and value types match
inputs: {
key1: "foo"
key2: 1
}
},
{
component: ComponentTwo, // error, key2 should be boolean
inputs: {
key1: ["foo"]
key2: 1
}
}
]
class ComponentOne {
key1!: string;
key2!: number;
}
class ComponentTwo {
key1!: Array<string>;
key2!: boolean;
}
是否可以在没有泛型的情况下编写类型 HowDoITypeThis
,使得第一个数组项中的 inputs
只允许 ComponentOne
的键和第二个中的 inputs
item 只允许 ComponentTwo
的键?
澄清一下,我希望这种类型能够处理动态数量的组件和组件类型。
答案 0 :(得分:3)
您可以使用映射类型来创建可能配对的联合,但这有一些限制。它将使用动态数量的组件/类型对,但不能使用未知数量。
当你通过映射类型创建联合时,基本上你所做的是创建一个键值对象类型,然后取所有值的联合。所以键会被丢弃,但我们在某个时候需要某种键来进行从 ComponentOne
到 {component: ComponentOne; inputs: React.ComponentProps<ComponentOne>}
的映射。我正在为在这种情况下该键是什么而苦苦挣扎,因为我没有看到任何类型的判别式。
(旁注:我发现您的命名令人困惑,因为您的 ComponentOne
是 props 类型而不是组件类型,所以我使用更清晰的名称。)
如果你像这样定义某种地图:
type PropTypes = {
one: ComponentOneProps;
two: ComponentTwoProps;
}
然后你可以使用这样的映射类型:
type ComponentAndProps = {
[K in keyof PropTypes]: {
component: React.ComponentType<PropTypes[K]>;
inputs: PropTypes[K];
}
}[keyof PropTypes];
这为您提供了所有有效配对的联合:
type ComponentAndProps = {
component: React.ComponentType<ComponentOneProps>;
inputs: ComponentOneProps;
} | {
component: React.ComponentType<ComponentTwoProps>;
inputs: ComponentTwoProps;
}
您的 HowDoITypeThis
是一个数组 ComponentAndProps[]
。如果您尝试将 ComponentOneProps
分配给 ComponentTwo
组件,则会出现大红色错误。
如果您希望您的数组接受任何类型的组件,您需要一种不同的方法,但强制 component
和 input
属性匹配。这确实需要泛型。它还要求您通过函数创建 arrayOfDifferentComponents
,因为我们无法说出其特定类型。我们需要推断它的泛型并检查提供的数组对于该泛型是否正确。
您可以创建一个映射类型,将 prop 类型的元组映射到 component
/inputs
对的元组:
type MapToPairing<T> = {
[K in keyof T]: {
component: React.ComponentType<T[K]>;
inputs: T[K];
}
}
并使用标识函数来确保您的数组有效:
const createComponentArray = <T extends {}[]>(array: MapToPairing<T>) => array;
当您的数组包含具有不匹配的 component
和 inputs
属性的元素时,您确实会收到预期的错误。
答案 1 :(得分:2)
您可以使用打字稿元组,例如
0
当然你也可以这样做
type HowDoITypeThis = [
{
component: ComponentOne;
inputs: {
someKeyOfComponentOne: ComponentInputA;
};
},
{
component: ComponentTwo;
inputs: {
someKeyOfComponentTwo: ComponentInputB;
};
}
]