TypeScript:从可变元组类型推断数据类型

TypeScript: inferring data types from variadic tuple types

可变元组类型允许我们提供函数的调用者,一个元组 return 类型 由提供给函数的元组驱动,如下所示:

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;
}]

现在考虑我们还想做两件事:

  1. 将每个数组元素中可以提供的项目缩小为 Data<TypeOfData>
  2. 类型
  3. Data<TypeOfData> 中提取我们要 returning 的类型;所以基本上使用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: number;
}, {
    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 in combination with the 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.

完成的

Playground