示例:
export interface Column<T> {
field: string;
columnFormatter?: (props: {
value: any/** field type inside T**/; data: T; node: any
}) => void;
}
字段是类型 T 中的属性名称,我怎么能说该值是该类型?
export interface IPurchase {
id: string;
name: string;
purchaseDate: Date;
}
let doSomethingWithMyDate: (myDate: Date) => (true);
const columns: Array<Column<IPurchase>> = [
{
field: "purchaseDate", /* "purchaseDate" must be inside IPurchase */
columnFormatter: ({ value /* must identify that this is a Date */ }) =>
doSomethingWithMyDate(value)
}];
为了表示field
属性与要columnFormatter
props
参数的value
属性类型之间的相关性,您需要Column<T>
为联合类型,每个键都有一个成员T
。 例如,给定您的IPurchase
示例,您需要Column<IPurchase>
type ColumnIPurchase = {
field: "id";
columnFormatter?: ((props: {
value: string;
data: IPurchase;
node: any;
}) => void);
} | {
field: "name";
columnFormatter?: ((props: {
value: string;
data: IPurchase;
node: any;
}) => void)
} | {
field: "purchaseDate";
columnFormatter?: ((props: {
value: Date;
data: IPurchase;
node: any;
}) => void);
}
这将按预期运行:
const columns: Array<Column<IPurchase>> = [
{
field: "purchaseDate",
columnFormatter: ({ value }) => doSomethingWithMyDate(value)
},
{
field: "name",
columnFormatter: ({ value }) => doSomethingWithMyDate(value) // error!
// string isn't a Date ----------------------------> ~~~~~
}
];
这就是我们想要的...我们怎么能写Column<T>
来做到这一点?
这是一种方法:
type Column<T> = { [K in keyof T]-?: {
field: K;
columnFormatter?: (props: { value: T[K]; data: T; node: any }) => void;
} }[keyof T]
这种类型的一般形式,{[K in keyof T]-?: F<K>}[keyof T]
,被称为分发对象类型,正如在microsoft/TypeScript#47109中创造的那样;我们正在keyof T
中的键上创建一个映射类型,然后立即用keyof T
索引到它,以便为keyof T
中的每个键K
获得F<K>
的联合。
特别是在这里,我们正在计算{ field: K; columnFormatter?: (props: { value: T[K]; data: T; node: any }) => void; }
其中K
是键的类型,T[K]
是对应于该键的属性值的类型。
您可以验证Column<IPurchase>
的评估结果是否完全符合所需类型。
操场链接到代码