给定类型,定义带有参数类型键的函数联合

时间:2020-01-21 19:04:19

标签: typescript typescript-generics

我具有以下类型,并且必须使用联合类型参数定义formatter

declare type TableHeadCell<T> = {
    key: keyof T;
    label: string;
    formatter?: (cell: T[keyof T], row?: T) => string;
};

declare type Product = {
    article: string;
    quantity: number
};

const myTHeadCell: TableHeadCell<Product> = {
   key: 'article',
   label: 'Article',
   formatter(cell: string | number, row: Product): string { /* ... */ }
}

我需要的是联合函数类型,这将使​​我可以使用任何一种参数类型来定义函数。最好缩小到key的类型。

const myTHeadCell: TableHeadCell<Product> = {
   key: 'article',
   label: 'Article',
   formatter(cell: string, row: Product): string { /* ... */ }
}

// or

const myTHeadCell: TableHeadCell<Product> = {
   key: 'quantity',
   label: 'Article',
   formatter(cell: number, row: Product): string { /* ... */ }
};

1 个答案:

答案 0 :(得分:3)

最简单的方法是将TableHeadCell<T>设为union类型,K中的每个keyof T都有一个成员。实现此目标的一种方法是创建一个映射类型,其中每个属性对应每个K,然后获得这些属性的并集:

type TableHeadCell<T> = { [K in keyof T]: {
  key: K;
  label: string;
  formatter?: (cell: T[K], row?: T) => string;
} }[keyof T];

现在您可以无误地编写以下内容:

const myTHeadCell1: TableHeadCell<Product> = {
  key: 'article',
  label: 'Article',
  formatter(cell: string, row?: Product): string { return "" }
}

const myTHeadCell2: TableHeadCell<Product> = {
  key: 'quantity',
  label: 'Article',
  formatter(cell: number, row?: Product): string { return "" }
};

编译器甚至会记住myTHeadCell1.formatter()带有一个string参数,而myTHeadCell2.formatter()带有一个number,因为control flow type analysis会暂时缩小并集的类型赋值的类型值:

if (myTHeadCell1.formatter) {
  myTHeadCell1.formatter(""); // okay
  myTHeadCell1.formatter(123); // error
}
if (myTHeadCell2.formatter) {
  myTHeadCell2.formatter(""); // error
  myTHeadCell2.formatter(123); // okay
}

请注意,我更改了格式化程序的实现,使得row是可选的。要匹配TableHeadCell<T>的定义,这是必需的。如果您希望在实现中需要row参数,则需要在带注释的类型中使用它,因为根据定义,应允许您使用一个参数调用TableHeadCell<T>.formatter!()。 (请确保您了解具有可选参数的函数类型与忽略多余参数的函数实现之间的区别,如in the TypeScript FAQ所述。)

好的,希望能有所帮助;祝你好运!

Playground link to code