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

问题描述

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

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. 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 typesExtract 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