泛型函数,其中数组参数构造泛型类型



我有一个泛型函数,它以数组为参数,我想构造由数组传递的泛型类型。这个函数工作得很好,但是我想添加一个类型来检查数组键是否构成泛型类型,如果不是,它应该抛出一个Typescript错误。

接口
interface OutputType {
id: string;
name: string;
age: number;
}
interface ArrayType {
key: string;
value: any;
}

的泛型函数
function TestType<T>(array: ArrayType[]): T {
let newObj = {} as T;
array.forEach((arrayItem) => {
newObj[arrayItem.key as keyof T] = arrayItem.value;
});
return newObj;
}

这应该导致TS **ERROR **,因为它缺少'id'属性

const array = [ 
{
key: "name",
value: "TestName",
},
{
key: "age",
value: 12,
},
] as ArrayType[];

这会清除TS错误

const array = [
{
key: "id",
value: "1",
},
{
key: "name",
value: "TestName",
},
{
key: "age",
value: 12,
},
] as ArrayType[];

下面是完整的示例代码:https://playcode.io/1019051

当我尝试为数组参数实现自定义类型时,我目前卡住了。

我想创建一个自定义类型来检查传入的数组,并根据泛型类型属性验证

这绝对是一个棘手的问题。要解决这个问题,您必须采用泛型类型T并从中生成所有有效的数组排列。

给定类型T

interface OutputType {
id: string;
name: string;
age: number;
}

有效数组的并集如下所示:

type Permutations = [{
key: "id";
value: string;
}, {
key: "name";
value: string;
}, {
key: "age";
value: number;
}] | [{
key: "id";
value: string;
}, {
key: "age";
value: number;
}, {
key: "name";
value: string;
}] | [...] | [...] | [...] | ...

可以使用泛型派生出这样的联合。

type CreatePermutations<
T extends Record<string, any>, 
K extends keyof T = keyof T, 
C extends keyof T = K
> = 
[K] extends [never]
? []
: K extends K
? [{ key: K, value: T[K] }, ...CreatePermutations<T, Exclude<C, K>>]
: never

,并在函数定义中使用此泛型类型。

function TestType<
T extends Record<string, any>
>(array: CreatePermutations<T> & ArrayType[]): T {
let newObj = {} as T;
array.forEach((arrayItem) => {
newObj[arrayItem.key as keyof T] = arrayItem.value;
});
return newObj;
}

当给定的函数输入与基于给定泛型T计算的排列不匹配时,将导致编译时错误。

// Error: Source has 2 element(s) but target requires 3.(2345)
TestType<OutputType>([ 
{
key: "name",
value: "TestName",
},
{
key: "age",
value: 12,
},
])
TestType<OutputType>([
{
key: "id",
value: "1",
},
{
key: "name",
value: "TestName",
},
{
key: "age",
value: 12,
},
])

这个实现的问题是它是组合爆炸。对于具有更多属性的对象,计算所有可能组合的并集将变得非常昂贵。

游乐场