没有泛型的类型推断?

时间:2021-05-21 05:23:48

标签: typescript typescript-generics

假设我有以下对象:

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 的键?

澄清一下,我希望这种类型能够处理动态数量的组件和组件类型。

2 个答案:

答案 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 组件,则会出现大红色错误。

TypeScript Playground Link


如果可用类型未知

如果您希望您的数组接受任何类型的组件,您需要一种不同的方法,但强制 componentinput 属性匹配。这确实需要泛型。它还要求您通过函数创建 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;

当您的数组包含具有不匹配的 componentinputs 属性的元素时,您确实会收到预期的错误。

TypeScript Playground Link

答案 1 :(得分:2)

您可以使用打字稿元组,例如

0

当然你也可以这样做

type HowDoITypeThis = [
   {
       component: ComponentOne;
       inputs: {
           someKeyOfComponentOne: ComponentInputA;
       };
   },
   {
       component: ComponentTwo;
       inputs: {
           someKeyOfComponentTwo: ComponentInputB;
       };
   }
]