如何实现低开销的[函数,...参数]泛型元组类型并让类型检查器验证元组合法性?
实现TypeScript自动校验函数+参数元组的批量定义
你想要的批量校验函数参数匹配的需求完全可以实现!核心是利用可变泛型元组和映射类型来逐个约束数组中的每个元组元素,让TypeScript自动检查每个函数对应的参数是否合法。
解决方案:批量校验函数expressions
直接定义一个泛型函数,它会自动校验传入的每一组[函数, 参数]元组是否匹配:
function expressions<T extends any[]>( ...items: { [K in keyof T]: T[K] extends [infer F, ...infer Args] ? F extends (...args: infer Params) => any ? Args extends Params ? [F, ...Params] : never : never : never } ): T { return items as T; }
使用示例
现在你可以直接批量传入元组,TypeScript会自动标记不合法的项:
let queue = expressions( [(a: number, b: string) => {}, 1, "ok"], // ✅ 完全匹配,合法 [(a: number) => {}, true], // ❌ 错误:boolean不能赋值给number类型的参数 [(a: number) => {}], // ❌ 错误:缺少必要的number类型参数 [(a: number, b: string) => {}, 1] // ❌ 错误:缺少string类型的第二个参数 );
原理拆解
这个函数的核心逻辑是通过映射类型逐个处理每个传入的元组:
- 用
T extends any[]捕获所有传入元组的整体类型; - 对每个元组元素
T[K],先推断出其中的函数F和传入的参数Args; - 再推断出函数
F本身要求的参数类型Params; - 检查
Args是否完全匹配Params:匹配则保留类型,不匹配则返回never,触发TypeScript的类型错误。
对比你之前的方案
- 单个
expression函数:需要逐个调用,确实繁琐; Expression[]直接定义数组:因为泛型使用了默认值,TypeScript会把所有元素统一成宽松的联合类型,无法逐个校验;- 这个批量函数既不需要逐个包装,又能自动完成每个元组的参数匹配校验,完美解决你的痛点。
额外:单独定义合法元组类型
如果你需要单独标记单个合法元组,可以用这个类型别名:
type ValidExpression<F extends (...args: any[]) => any> = [F, ...Parameters<F>];
不过单独使用ValidExpression[]还是无法自动校验每个元素,必须通过函数来强制约束每个元素的具体类型。
内容的提问来源于stack exchange,提问作者Ian
相关产品推荐
相关产品推荐

