args 在 TypeScript 中通常指函数参数 ,特别是剩余参数(rest parameters) 。让我详细解释各种用法和场景。
1. 剩余参数(Rest Parameters) 基本语法 1 2 3 4 5 6 7 8 function sum (...args: number [] ): number { return args.reduce ((total, current ) => total + current, 0 ); } console .log (sum (1 , 2 , 3 , 4 , 5 )); console .log (sum (10 , 20 ));
带固定参数的剩余参数 1 2 3 4 5 6 7 function greet (greeting: string , ...names: string [] ): string { return `${greeting} , ${names.join(', ' )} !` ; } console .log (greet ("Hello" , "Alice" , "Bob" , "Charlie" ));
2. 函数参数对象(Arguments Object) 在 TypeScript/JavaScript 中,每个函数内部都可以访问 arguments 对象:
1 2 3 4 5 6 7 8 9 10 function traditionalSum ( ) { let total = 0 ; for (let i = 0 ; i < arguments .length ; i++) { total += arguments [i]; } return total; } console .log (traditionalSum (1 , 2 , 3 ));
注意 :arguments 不是数组,而是类数组对象 。
3. 元组类型的剩余参数 TypeScript 允许对剩余参数使用元组类型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function processData (name: string , ...[first, second]: [number , number ] ): void { console .log (`Name: ${name} , Numbers: ${first} , ${second} ` ); } processData ("John" , 10 , 20 ); function mixedArgs (...args: [string , number , ...boolean []] ): void { console .log (args); } mixedArgs ("hello" , 42 , true , false , true );
4. 在箭头函数中的使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 const multiplyAll = (...numbers : number []): number => { return numbers.reduce ((product, num ) => product * num, 1 ); }; console .log (multiplyAll (2 , 3 , 4 )); const mergeArrays = <T>(...arrays : T[][]): T[] => { return arrays.flat (); }; const result = mergeArrays ([1 , 2 ], [3 , 4 ], [5 , 6 ]);
5. 实际应用场景 场景 1:高阶函数和装饰器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function logExecution<T extends (...args : any []) => any >( target : T ): (...args: Parameters<T> ) => ReturnType <T> { return function (...args: Parameters<T> ): ReturnType <T> { console .log (`函数被调用,参数:` , args); const result = target (...args); console .log (`函数返回:` , result); return result; }; } const loggedSum = logExecution (sum);loggedSum (1 , 2 , 3 );
场景 2:配置合并 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 interface Config { timeout?: number ; retries?: number ; baseURL?: string ; } function createApiClient (defaultConfig: Config, ...configs: Partial<Config>[] ): Config { return configs.reduce ((merged, config ) => ({ ...merged, ...config }), defaultConfig); } const client = createApiClient ( { timeout : 5000 , baseURL : "/api" }, { retries : 3 }, { timeout : 3000 } );
场景 3:事件处理器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class EventEmitter { private events : Map <string , Function []> = new Map (); on (event : string , ...handlers : ((...args: any [] ) => void )[]): void { if (!this .events .has (event)) { this .events .set (event, []); } this .events .get (event)!.push (...handlers); } emit (event : string , ...args : any []): void { const handlers = this .events .get (event) || []; handlers.forEach (handler => handler (...args)); } } const emitter = new EventEmitter ();emitter.on ("message" , (msg: string , priority: number ) => { console .log (`消息: ${msg} , 优先级: ${priority} ` ); }); emitter.emit ("message" , "Hello World" , 1 );
6. 泛型与剩余参数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function callAll<T extends any []>( ...functions : ((...args: T ) => void )[] ): (...args: T ) => void { return (...args: T ) => { functions.forEach (fn => fn (...args)); }; } const logger = (msg: string , count: number ) => console .log (msg, count);const storage = (msg: string , count: number ) => localStorage .setItem ('last' , msg);const combined = callAll (logger, storage);combined ("test" , 5 );
7. 类型工具与 args Parameters 工具类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 type SumParams = Parameters <typeof sum>; type GreetParams = Parameters <typeof greet>; function withRetry<T extends any [], R>( fn : (...args: T ) => R, retries : number ): (...args: T ) => R { return function (...args: T ): R { let lastError : Error ; for (let i = 0 ; i < retries; i++) { try { return fn (...args); } catch (error) { lastError = error as Error ; } } throw lastError!; }; }
8. 常见模式和最佳实践 模式 1:参数验证 1 2 3 4 5 6 7 8 9 10 11 12 13 14 function validateAndProcess (...inputs: (string | number )[] ): void { if (inputs.length === 0 ) { throw new Error ("至少需要一个参数" ); } inputs.forEach ((input, index ) => { if (input === null || input === undefined ) { throw new Error (`参数 ${index} 不能为 null 或 undefined` ); } }); }
模式 2:函数组合 1 2 3 4 5 6 7 8 9 10 11 12 13 14 function compose<T extends any []>( ...functions : ((...args: T ) => void )[] ): (...args: T ) => void { return (...args: T ) => { functions.forEach (fn => { try { fn (...args); } catch (error) { console .error ('函数执行错误:' , error); } }); }; }
模式 3:条件参数处理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function flexibleProcessor ( required: string , ...optional: (number | string )[] ): { required : string ; optional : (number | string )[] } { const processedOptional = optional.map (arg => { if (typeof arg === 'string' ) { return arg.toUpperCase (); } return arg * 2 ; }); return { required, optional : processedOptional }; }
9. 注意事项 注意 1:arguments vs 剩余参数 1 2 3 4 5 6 7 8 9 10 function oldWay ( ) { console .log (arguments [0 ], arguments [1 ]); } function newWay (...args: [string , number ] ) { console .log (args[0 ], args[1 ]); }
注意 2:性能考虑 1 2 3 4 5 6 7 8 9 10 function optimizedSum (a: number , b: number , c?: number , d?: number ): number { let total = a + b; if (c !== undefined ) total += c; if (d !== undefined ) total += d; return total; }
💎 总结 在 TypeScript 中,args 主要涉及:
剩余参数 (...args):收集多个参数到数组
arguments 对象 :函数内可访问的类数组对象
元组类型的剩余参数 :提供更精确的类型控制
泛型剩余参数 :保持类型安全的可变参数
最佳实践 :
优先使用剩余参数而非 arguments 对象
为剩余参数提供明确的类型注解
在需要精确类型控制时使用元组类型
考虑性能影响,在热路径中避免不必要的数组创建
args 是 TypeScript 函数编程中的重要概念,合理使用可以大大增强代码的灵活性和类型安全性。