“任意”泛型类型

时间:2021-05-02 21:53:03

标签: typescript typescript-generics react-typescript

是否有任何 TypeScript 解决方案,可以帮助我拥有“无限”数量的泛型类型,当然,无需键入所有类型?

示例如下:

type Args<T extends React.ComponentType<any>> = { component: T, presetProps: React.ComponentProps<T>};

function buildComponents<T extends React.ComponentType<any>>(...args: Args<T>[] ) : any

function componentJ({name, age}: {name: string, age: number}){
  return <h1>123</h1>
}

function componentI({ age}: { age: number}){
  return <h1>123</h1>
}

buildComponents({component:componentJ, presetProps:{name: "Jon", age: 12}}, 
                {component: componentI, presetProps:{age: 44}})

使用此代码,我在 {component: componentI, presetProps:{age: 44}} 上遇到错误,因为它错过了 name,但我希望它从 componentI 而不是从 {{ 1}},就是这种情况。

1 个答案:

答案 0 :(得分:5)

您可能希望使 buildComponents 函数泛型化,而不是在要传递给 Args 的类型的 union 中,而是在此类类型的 tuple 中。编译器不希望从异构列表(其中元素可能具有不同类型)推断联合,因为这通常是一个错误:

function foo<T>(...args: T[]) { }
foo(1, 2, "3", 4); // error!
// -----> ~~~ string is not a number

另一方面,元组类型旨在支持异构列表:

function bar<T extends any[]>(...args: T) {}
bar(1, 2, "3", 4); // okay

那么让我们用 buildComponents() 试试:

declare function buildComponents<T extends React.ComponentType<any>[]>(
  ...args: { [I in keyof T]: Args<Extract<T[I], React.ComponentType<any>>> }
): any;

我在那里所做的是将 map the tuple type T 转换为一个新元组,以便每个元素 T[I] 变成 Args<T[I]>the Extract utility type 有一些技巧可以解决编译器错误(请参阅 microsoft/TypeScript#27995)。但它有效:

buildComponents(
  { component: componentJ, presetProps: { name: "Jon", age: 12 } },
  { component: componentI, presetProps: { age: 44 } }
); // okay

另一种方法是使 T 成为 props 类型的元组,而不是组件类型。干净一点:

declare function buildComponents<P extends any[]>(
  ...args: { [I in keyof P]: { component: React.ComponentType<P[I]>, presetProps: P[I] } }
): any;

并且还在呼叫站点工作:

buildComponents(
  { component: componentJ, presetProps: { name: "Jon", age: 12 } },
  { component: componentI, presetProps: { age: 44 } }
); // okay

Playground link to code

相关问题