[英]Type inference without generics?
Suppose I have the following objects:假设我有以下对象:
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;
}
Is it possible to write the type HowDoITypeThis
without generics, such that the inputs
in the first array item only allow keys of ComponentOne
and the inputs
in the second item only allow keys of ComponentTwo
?是否可以在没有 generics 的情况下编写类型
HowDoITypeThis
,这样第一个数组项中的inputs
只允许ComponentOne
的键,而第二项中的inputs
只允许ComponentTwo
的键?
Just to clarify, I want this type to work with a dynamic number of components and component types.澄清一下,我希望这种类型能够与动态数量的组件和组件类型一起使用。
You can used mapped types to create a union of possible pairings, but this has some limitations.您可以使用映射类型来创建可能配对的联合,但这有一些限制。 It will work with a dynamic number of component/type pairs, but not an unknown number.
它将使用动态数量的组件/类型对,但不是未知数量。
When you are creating a union through mapped types, basically what you do is create a key-value object type and then take the union of all the values.当您通过映射类型创建联合时,基本上您所做的就是创建一个键值 object 类型,然后取所有值的联合。 So the keys get discarded, but we need some sort of key at some point in order to do the mapping from
ComponentOne
to {component: ComponentOne; inputs: React.ComponentProps<ComponentOne>}
所以键被丢弃了,但是我们在某个时候需要某种键来进行从
ComponentOne
到{component: ComponentOne; inputs: React.ComponentProps<ComponentOne>}
的映射。 {component: ComponentOne; inputs: React.ComponentProps<ComponentOne>}
. {component: ComponentOne; inputs: React.ComponentProps<ComponentOne>}
。 I'm struggling with what that key would be in this scenario as I'm not seeing any sort of discriminant.我正在努力解决在这种情况下该键的含义,因为我没有看到任何类型的判别。
(side note: I find your naming to be confusing because your ComponentOne
is the props type rather than the component type, so I'm using names that are clearer.) (旁注:我发现您的命名令人困惑,因为您的
ComponentOne
是道具类型而不是组件类型,所以我使用的名称更清晰。)
If you define some sort of map like this:如果您像这样定义某种 map:
type PropTypes = {
one: ComponentOneProps;
two: ComponentTwoProps;
}
Then you can use a mapped type like this:然后你可以使用这样的映射类型:
type ComponentAndProps = {
[K in keyof PropTypes]: {
component: React.ComponentType<PropTypes[K]>;
inputs: PropTypes[K];
}
}[keyof PropTypes];
Which gives you the union of all valid pairings:这为您提供了所有有效配对的联合:
type ComponentAndProps = {
component: React.ComponentType<ComponentOneProps>;
inputs: ComponentOneProps;
} | {
component: React.ComponentType<ComponentTwoProps>;
inputs: ComponentTwoProps;
}
Your HowDoITypeThis
is an array ComponentAndProps[]
.您的
HowDoITypeThis
是一个数组ComponentAndProps[]
。 You'll get a big red error if you try to assign ComponentOneProps
to a ComponentTwo
component.如果您尝试将
ComponentOneProps
分配给ComponentTwo
组件,则会收到一个很大的红色错误。
TypeScript Playground Link TypeScript 游乐场链接
You need a different approach if you want your array to accept any type of component, but enforce that the component
and input
properties match.如果您希望数组接受任何类型的组件,但需要强制
component
和input
属性匹配,则需要一种不同的方法。 This does require generics.这确实需要 generics。 It also requires that you create
arrayOfDifferentComponents
through a function because we cannot say its specific type.它还要求您通过 function 创建
arrayOfDifferentComponents
,因为我们无法说出它的具体类型。 We need to infer its generic and check that that the provided array is correct for that generic.我们需要推断它的泛型并检查提供的数组对于该泛型是否正确。
You can create a mapped type that maps from a tuple of prop types to a tuple of component
/ inputs
pairs:您可以创建一个映射类型,将 prop 类型的元组映射到
component
/ inputs
对的元组:
type MapToPairing<T> = {
[K in keyof T]: {
component: React.ComponentType<T[K]>;
inputs: T[K];
}
}
And use an identity function to make sure that your array is valid:并使用身份 function 确保您的数组有效:
const createComponentArray = <T extends {}[]>(array: MapToPairing<T>) => array;
You do get the expected error when your array includes an element with mismatched component
and inputs
properties.当您的数组包含具有不匹配的
component
和inputs
属性的元素时,您确实会收到预期的错误。
you can use typescript tuple such as您可以使用 typescript 元组,例如
type HowDoITypeThis = [
{
component: ComponentOne;
inputs: {
someKeyOfComponentOne: ComponentInputA;
};
},
{
component: ComponentTwo;
inputs: {
someKeyOfComponentTwo: ComponentInputB;
};
}
]
of course you can also do this当然你也可以这样做
interface MyGenericA<T, U> {
component: T;
inputs: U;
}
type HowDoITypeThis = [
MyGenericA<ComponentOne, YourInputTypeA>,
MyGenericA<ComponentTwo, YourInputTypeB>
]
you basically had it:你基本上有它:
type HowDoITypeThis = [
{
component: ComponentOne,
inputs: {
someKeyOfComponentOne: ComponentOne[someKeyOfComponentOne]
}
},
{
component: ComponentTwo,
inputs: {
someKeyOfComponentTwo: ComponentTwo[someKeyOfComponentTwo]
}
}
]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.