TypeScript中如何定义支持多类型参数的函数类型(无需rest参数)
解决方案
要实现满足你需求的函数类型定义(用于方法装饰器,编译时校验参数类型),可以通过泛型结合条件类型的方式约束方法的参数元组,确保每个参数都是string或number类型,同时允许实现时单独定义每个参数的具体类型。
步骤1:定义校验装饰器
创建泛型装饰器,通过递归条件类型检查参数元组的每个元素是否符合要求:
// 递归校验参数元组的每个元素是否为string或number type IsValidArgs<T extends any[]> = T extends [infer First, ...infer Rest] ? First extends string | number ? IsValidArgs<Rest> : never : T; // 仅接受参数全为string/number的方法的装饰器 function validateArgsDecorator<Args extends any[], Return>( target: any, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<(...args: Args) => Return> ): void { // 触发编译时校验:参数不符合要求时,Check会变为never,导致类型不兼容 type Check = IsValidArgs<Args>; const _check: Check = null!; // 此处添加你的装饰器业务逻辑 console.log(`Decorator applied to method: ${String(propertyKey)}`); }
步骤2:使用装饰器校验方法
将装饰器应用到类方法上,编译时会自动校验参数类型:
class ExampleClass { // ✅ 合法:参数为string和number @validateArgsDecorator validMethod(arg1: string, arg2: number) { console.log(arg1, arg2); } // ❌ 非法:参数包含boolean类型,编译报错 @validateArgsDecorator invalidMethod(arg1: boolean) { console.log(arg1); } // ✅ 合法:任意数量的string/number参数 @validateArgsDecorator multiArgMethod(a: number, b: string, c: number) { console.log(a, b, c); } }
原理说明
- 条件类型
IsValidArgs会递归遍历参数元组,只要有一个元素不是string或number,就返回never类型。 - 装饰器内部通过
const _check: Check = null!触发校验:参数不符合要求时,Check为never,无法完成赋值,直接抛出编译错误。 - 合法参数的元组会通过递归检查,
Check与原参数元组类型一致,不会触发错误。
简化函数类型定义(非装饰器场景)
如果只是需要定义满足条件的函数类型,可使用泛型元组约束:
// 任意参数数量、每个参数为string/number的函数类型 type ValidFunction<T extends (string | number)[] = (string | number)[]> = (...args: T) => void; // ✅ 合法:单独定义每个参数类型 const func1: ValidFunction<[string, number]> = (arg1: string, arg2: number) => { console.log(arg1, arg2); }; // ✅ 合法:任意数量的参数 const func2: ValidFunction<[number, string, number]> = (a, b, c) => { console.log(a, b, c); };
这种方式需要显式指定泛型参数(参数元组类型),适合明确参数数量和类型的场景。
内容的提问来源于stack exchange,提问作者Chris Stack
相关产品推荐
相关产品推荐

