我看到一些关于推断数组文字长度的问题的答案。问题在于,当您将数组文字传递给函数时,编译器通常会将其扩展为数组,并且不会将其解释为固定长度的元组。这通常是您想要的;通常数组会改变长度。当您希望编译器将其[1, 2]
视为一对而不是数组时,您可以给编译器一个提示:
function requireTwoSameLengthArrays<
T extends readonly [] | readonly any[]
>(t: T, u: { [K in keyof T]: any }): void { }
请注意,泛型类型参数T
的泛型约束是空元组类型[]
和数组类型的联合any[]
。(不用担心readonly
; 这个修饰符使函数更通用,而不是更具体,因为它string[]
可以赋值给readonly string[]
而不是反之亦然。)在联合中拥有空元组类型不会改变可以成为的东西的种类T
(之后所有,any[]
已经包括空元组[]
)。但它确实给编译器一个提示,即需要元组类型。
所以编译器会推断[1, 2]
as[number, number]
而不是 as number[]
。
检查上面的签名,您会看到u
参数是映射的数组/元组类型。如果T
是元组,{[K in keyof T]: any}
则是与 长度相同的元组T
。
让我们看看它的实际效果:
requireTwoSameLengthArrays([1, 2], [3, 4]); // okay
requireTwoSameLengthArrays([1, 2], [3]); // error! property 1 is missing in [number]!
requireTwoSameLengthArrays([1, 2], [3, 4, 5]); // error! length is incompatible!
万岁!
请注意,如果编译器已经忘记了元组的长度,这将不起作用:
const oops = [1, 2]; // number[]
requireTwoSameLengthArrays(oops, [1, 2, 3]); // okay because both are of unknown length
的类型oops
被推断为number[]
,并将其传递给requireTwoSameLengthArrays()
无法撤消该推断。太晚了。如果您希望编译器只拒绝完全未知长度的数组,您可以这样做:
function requireTwoSameLengthTuples<
T extends (readonly [] | readonly any[]) & (
number extends T["length"] ? readonly [] : unknown
)>(t: T, u: { [K in keyof T]: any }): void { }
这是更丑陋的,但它所做的是检查是否T
有长度number
而不是某些特定的数字文字。如果是这样,它会通过要求一个空元组来阻止匹配。这有点奇怪,但它有效:
requireTwoSameLengthTuples([1, 2], [3, 4]); // okay
requireTwoSameLengthTuples([1, 2], [3]); // error! [number] not [any, any]
requireTwoSameLengthTuples([1, 2], [3, 4, 5]); // error! ]number, number, number]
requireTwoSameLengthTuples(oops, [1, 2, 3]); // error on oops!
// Types of property 'length' are incompatible.
好的,希望有帮助;祝你好运!
Playground 链接到代码