长话短说,出于复杂的原因,我需要能够声明一个接口(使用数组签名)以1开始,或者至少[0]为空。这可能吗?
我已经尝试过:
interface ItemCollection<T> extends Collection
{
[index: number]: [null, ...Function[]];
addComp(): void;
}
显然只是说,“ ItemCollection [0 ...]是一个元组”,不是我想要的。
也尝试过:
interface ItemCollection<T> extends Collection
{
[0]: null;
[index: number]: Function;
}
但是我只收到一条错误消息,“类型为'null'的属性'[0]'无法分配给数字索引类型为'Function'.ts(2412)” 所以显然不是答案。
我可以使用标准变量来做到这一点:
tmp: [null, ...Function[]];
这很好用,但是不一样。
答案 0 :(得分:3)
知道了。但这需要很多递归魔术:
首先让我们声明utils从元组中添加/删除元素:
type PrependTuple<A, T extends Array<any>> =
A extends undefined ? T :
(((a: A, ...b: T) => void) extends (...a: infer I) => void ? I : [])
type RemoveFirstFromTuple<T extends any[]> =
T['length'] extends 0 ? undefined :
(((...b: T) => void) extends (a, ...b: infer I) => void ? I : [])
type FirstFromTuple<T extends any[]> =
T['length'] extends 0 ? undefined : T[0]
然后,我们必须声明将使用N
个项目创建元组的utils:
type NumberToTuple<N extends number, L extends Array<any> = []> = {
true: L;
false: NumberToTuple<N, PrependTuple<1, L>>;
}[L['length'] extends N ? "true" : "false"];
这将递归地增加L
元组的大小,直到达到我们想要的长度为止。
下一步反向元组util(基于相同的想法)
type ReverseTuple<T extends Array<any>, L extends Array<any> = []> = {
true: L;
false: ReverseTuple<T, PrependTuple< T[L['length']] , L>>;
}[L['length'] extends T['length'] ? "true" : "false"];
type R4 = ReverseTuple<[1, 2, 3, 4]>; // [4,3,2,1]
最后一个需要使用的工具以减少数量:
type Decrease<I extends number> = RemoveFirstFromTuple<NumberToTuple<I>>['length']
它正在创建具有确切长度的元组并删除第一个元素。结果就是剪切的元组的大小。
cream de la cream:将应用逻辑的迭代器:
type Iter<N extends number, Items extends any[], L extends Array<any> = []> = {
true: L;
false: Iter<N, Items, PrependTuple<L['length'] extends N ? unknown : Items[Decrease<L['length']>] , L>>
}[L["length"] extends N ? "true" : "false"];
以sam方式进行迭代,但是在最后一步(当L['length'] extends N
时),我们在unknown
之前添加了元组。因为我们增加了最终元组的大小(Result ['length'] === Items ['length'] + 1),所以我们不得不减少索引。
此外,因为我们在前面添加(而不是追加),所以我们必须反转元组。因此最终的泛型将如下所示:
type FromFirstTuple<T extends Array<any>> = ReverseTuple<Iter<PrependTuple<1, T>['length'], T>>
type Result = FromFirstTuple<[1,2,3]> // [unknown, 1, 2, 3]
答案 1 :(得分:1)
我想这就是您想要的...(也可以考虑将其标记为接受)
type Unshift<T extends any[]> =
((a: null, ...b: T) => void) extends ((...ab: infer R) => void)
? R : never
type foo = Unshift<[1, 2, 3]> // [null, 1, 2, 3]