我正试图强制类型为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]);
但是类型MyType
的ofc不会包含所有可能的索引,因此我试图以其他方式编写。 { [index: number]: 9}
不是这样做的好方法,因为它需要将所有值设置为9
。我还尝试了一些映射类型的组合,但没有成功
我该如何写MyType
来解决这个问题?
答案 0 :(得分:2)
您确实可以使用映射类型。这是我输入forceInArray()
的方式:
declare function forceInArray<
R extends number,
T extends (ReadonlyArray<number> | readonly [R]) &
{ [K in keyof T]: { [P in K]: R } }[number]
>(required: R, input: T): void;
这里的一些复杂性与说服编译器将数组文字值推断为元组类型,将数字文字值推断为数字文字类型有关(其中的[R]
处理这两者)。有一些black magic involved。我也希望一些有趣的边缘情况会出现在诸如number
,0元素元组等加宽类型周围。最后,我使用了readonly
数组,因此人们可以使用const
assertions想要(如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
看起来不错。希望能有所帮助;祝你好运!