问题描述
可变元组类型允许我们提供函数的调用者,元组返回类型 由提供给函数的元组驱动,如下所示:
function makeArrayAsConstItems<T extends readonly any[]>(...arr: [...T]): {[K in keyof T]: {item: T[K]} } {
return arr.map(item => ({ item })) as any;
}
const arrayAsConstItems = makeArrayAsConstItems('cfgh',1,new Date());
// this is the type
const arrayAsConstItems: [{
item: string;
},{
item: number;
},{
item: Date;
}]
现在考虑我们还想做两件事:
- 将每个数组元素中可以提供的项缩小为
Data<TypeOfData>
类型 - 从
Data<TypeOfData>
中提取我们将要返回的类型;所以基本上使用TypeOfData
interface Data<TypeOfData = unkNown> {
data: TypeOfData;
}
function makeArrayAsConstItemsForDataTypesOnly<T extends readonly Data[]>(...arr: [...T]): {[K in keyof T]: {item: T[K]} } {
return arr.map(item => ({ item })) as any;
}
const arrayAsConstItemsForDataTypesOnly = makeArrayAsConstItemsForDataTypesOnly(
{ data: 'cfgh' },{ data: 1 },{ data: new Date() }
)
我们需要做什么才能使 arrayAsConstItemsForDataTypesOnly
具有与 arrayAsConstItems
相同的类型?
目前的类型是:
const arrayAsConstItemsForDataTypesOnly: [{
item: {
data: string;
};
},{
item: {
data: number;
};
},{
item: {
data: Date;
};
}]
我们希望它是:
const arrayAsConstItemsForDataTypesOnly: [{
item: string;
},{
item: Date;
}]
这是@A_blop 的建议:
function makeArrayAsConstItemsForDataTypesOnly<T extends readonly Data[]>(...arr: [...T]): {[K in keyof T]: {item: Extract<T[K],Data>["data"]} } {
return arr.map(item => ({ item })) as any;
}
解决方法
我们可以通过将 lookup types 与 Extract
utility type 结合使用来做到这一点:
function fn<T extends readonly Data[]>(...arr: [...T]):
{ [K in keyof T]: { item: Extract<T[K],Data>["data"] } } {/* impl */}
const arrayAsConstItemsForDataTypesOnly = fn(
{ data: 'cfgh' },{ data: 1 },{ data: new Date() }
)
/*
[{
item: string;
},{
item: number;
},{
item: Date;
}]
*/
由于 TypeScript 无法进一步解析 T[K]
,我们首先需要再次说服它,结果类型具有可通过查找运算符访问的 data
属性。这是由Extract
完成的。