我看到一些关于推断数组文字长度的问题的答案。问题在于,当您将数组文字传递给函数时,编译器通常会将其扩展为数组并且不会将其解释为固定长度的元组。这通常是您想要的;数组经常改变长度。当您希望编译器将[1, 2] 视为一对而不是数组时,您可以给编译器一个提示:
function requireTwoSameLengthArrays<
T extends readonly [] | readonly any[]
>(t: T, u: { [K in keyof T]: any }): void { }
请注意,泛型类型参数T 的generic constraint 是空元组类型[] 和数组类型any[] 的联合。 (不要担心readonly;这个修饰符使函数更通用,而不是更具体,因为string[] 可分配给readonly string[],反之亦然。)在联合中拥有空元组类型不会改变T 可以是 种类 的事物(毕竟,any[] 已经包含空元组 [])。但它确实给编译器一个提示需要元组类型。
因此编译器会将[1, 2] 推断为[number, number] 而不是number[]。
检查上面的签名,您会看到u 参数是mapped array/tuple type。如果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 而不是某些特定的numeric literal。如果是这样,它会通过要求一个空元组来阻止匹配。这有点奇怪,但它有效:
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 link to code