TypeScript:元组作为剩余参数报错的原因与解决问询
问题:TypeScript中如何让编译器识别元组作为剩余参数的数组类型?
我定义了一个用于判断类型是固定长度元组还是数组的类型,想借此推断函数参数类型。实际调用时,参数one、two、arr都能正确推断,但在? (...params: T[K]) => void处报错:A rest parameter must be of an array type。明明元组属于数组类型,请问怎么引导编译器正确识别?
代码示例
type ANumber = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10; type IsTuple<Type> = Type extends readonly unknown[] ? Type['length'] extends ANumber ? true : false : false; function fn<T extends Record<keyof T, unknown>>() { return function withConfig(config: { [K in keyof T]: IsTuple<T[K]> extends true ? (...params: T[K]) => void : (param: T[K]) => void }) {}; } fn<{ tupleType: [number, number], arrayType: number[] }>()({ tupleType: (one, two) => {}, arrayType: (arr) => {} })
报错信息
A rest parameter must be of an array type
解决方案
问题核心在于:仅通过IsTuple<T[K]> extends true的条件判断,TypeScript无法反向推导出T[K]一定是数组/元组类型,因此会认为剩余参数的类型不符合要求。我们需要先明确约束T[K]为数组类型,再区分元组和数组:
修改后的代码
type ANumber = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10; type IsTuple<Type> = Type extends readonly unknown[] ? Type['length'] extends ANumber ? true : false : false; function fn<T extends Record<keyof T, unknown>>() { return function withConfig(config: { [K in keyof T]: T[K] extends readonly unknown[] ? IsTuple<T[K]> extends true ? (...params: T[K]) => void : (param: T[K]) => void : (param: T[K]) => void }) {}; } fn<{ tupleType: [number, number], arrayType: number[] }>()({ tupleType: (one, two) => {}, arrayType: (arr) => {} })
更简洁的写法
直接利用元组length为字面量类型、数组length为number类型的特性合并判断:
function fn<T extends Record<keyof T, unknown>>() { return function withConfig(config: { [K in keyof T]: T[K] extends readonly unknown[] ? T[K]['length'] extends number & ANumber ? (...params: T[K]) => void : (param: T[K]) => void : (param: T[K]) => void }) {}; }
原理说明
先通过T[K] extends readonly unknown[]明确告诉编译器:当前分支下的T[K]是数组类型(包括元组),此时剩余参数...params: T[K]的类型就会被正确识别。后续再通过IsTuple或length的特性区分元组和数组,生成对应的函数签名。
内容的提问来源于stack exchange,提问作者Andy Jessop
相关产品推荐
相关产品推荐

