我试图强制number[]
类型的参数至少包含一个值9
元素。
到目前为止,我已经得到了:
type MyType<Required> = { 0: Required } | { 1: Required } | { 2: Required };
declare function forceInArray<
Required extends number,
Type extends number[] & MyType<Required>
>(
required: Required,
input: Type
): void;
// should fail type-checking
forceInArray(9, []);
forceInArray(9, [1, 2]);
forceInArray(9, { 0: 9 });
// should type-check correctly
forceInArray(9, [9]);
forceInArray(9, [9, 9]);
forceInArray(9, [9, 2, 3, 4]);
forceInArray(9, [1, 9, 3, 4]);
forceInArray(9, [1, 2, 9, 4]);
forceInArray(9, [1, 2, 3, 9]);
链接到 TS 游乐场
但是 ofc 类型MyType
不会包含所有可能的索引,所以我正在尝试以其他方式编写它。{ [index: number]: 9}
不是这样做的好方法,因为它要求所有值都设置为9
.我也尝试过映射类型的一些组合,但没有成功
我怎样才能写MyType
才能解决这个问题?
你确实可以使用映射类型。 以下是我键入forceInArray()
的方式:
declare function forceInArray<
R extends number,
T extends number[],
>(required: R, input: [...T] extends { [K in keyof T]: { [P in K]: R } }[number] ?
readonly [...T] : never): void;
这里的一些复杂性与说服编译器将数组文本值推断为元组类型以及将数字文本值推断为数字文本类型有关(其中有[...T]
可以处理两者(。 这其中涉及一些黑魔法。 此外,我希望在number
、0 元素元组等加宽类型周围会出现一些有趣的边缘情况。 最后,我使用了readonly
数组,以便人们可以根据需要使用const
断言(如forceInArray(9, [1,2,9] as const)
(。
好的,问题的核心:{ [ K in keyof T]: { [P in K]: R } }[number]
类型非常像您的MyType
类型别名。 如果T
是[4, 5, 6, 7, 8]
而R
是9
的,那么该类型就变成了[{0: 9}, {1: 9}, {2: 9}, {3: 9}, {4: 9}][number]
,或者{0: 9} | {1: 9} | {2: 9} | {3: 9} | {4: 9}
。 请注意它是如何扩展的,以具有与T
长度一样多的项。
让我们看看它是否有效:
forceInArray(9, []); // error
forceInArray(9, [1, 2]); // error
forceInArray(9, { 0: 9 }); // error
forceInArray(9, [9]); // okay
forceInArray(9, [9, 9]); // okay
forceInArray(9, [9, 2, 3, 4]); // okay
forceInArray(9, [1, 9, 3, 4]); // okay
forceInArray(9, [1, 2, 9, 4]); // okay
forceInArray(9, [1, 2, 3, 9]); // okay
forceInArray(9, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); // okay
看起来不错。 希望有帮助;祝你好运!
链接到代码