简体   繁体   English

没有 generics 的类型推断?

[英]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.澄清一下,我希望这种类型能够与动态数量的组件和组件类型一起使用。

If the Available Types are Known如果可用类型已知

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 游乐场链接


If the Available Types are Unknown如果可用类型未知

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.如果您希望数组接受任何类型的组件,但需要强制componentinput属性匹配,则需要一种不同的方法。 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.当您的数组包含具有不匹配的componentinputs属性的元素时,您确实会收到预期的错误。

TypeScript Playground Link TypeScript 游乐场链接

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM