TypeScript中如何为多类型函数的参数数组实现精准类型校验?
问题
需要存储多个仅含单个参数的不同函数及其对应的参数值。目前仅能实现单一类型函数的类型校验,希望能同时传入多种类型函数,并为每个函数的参数提供正确的类型校验。
现有代码示例:
type WalkOptions = { x: number speed: number } type JumpOptions = { y: number speed: number } type ShootOptions = { type: string duration: number } const walk = (options: WalkOptions)=>{} const jump = (options: JumpOptions)=>{} const shoot = (options: ShootOptions)=>{} type Action<T extends (options: any) => void> = { command: T args: Parameters<T>[0] } function add<T extends (options: any) => void>(...actions: Action<T>[]){}
当前调用add({command: walk, args:{x: 10, speed: 1}})或传入多个同类型函数时可正常校验,但传入不同类型函数(如同时传入walk和jump)会触发类型错误。
请问如何修改实现,使add函数支持传入多种类型函数,同时保证每个Action的args与对应command的参数类型匹配?另外,能否创建带类型校验的Action数组,用于add(...actionArray)的调用?
解决方案
1. 修改add函数以支持多类型Action
原代码中add函数的泛型T强制所有传入的Action必须是同一种函数类型,这是混合类型报错的核心原因。我们需要让add接受任意数量的不同类型Action,同时保留每个Action内部command和args的类型关联。
修改后的完整代码:
type WalkOptions = { x: number speed: number } type JumpOptions = { y: number speed: number } type ShootOptions = { type: string duration: number } const walk = (options: WalkOptions)=>{} const jump = (options: JumpOptions)=>{} const shoot = (options: ShootOptions)=>{} // 保留Action的类型关联:command的参数类型决定args的类型 type Action<F extends (args: any) => void> = { command: F args: Parameters<F>[0] } // 修改add函数,允许传入任意多个不同类型的Action实例 function add(...actions: Array<Action<any>>){}
此时调用add传入混合类型函数会自动校验每个Action的args是否匹配对应command的参数类型:
// 正确调用:每个args都匹配对应command的参数 add( {command: walk, args:{x: 10, speed: 1}}, {command: jump, args:{y: 20, speed: 2}}, {command: shoot, args:{type: "fire", duration: 5}} ); // 错误调用:walk的args缺少x参数,TypeScript会触发类型报错 add({command: walk, args:{speed: 1}});
2. 创建带类型校验的Action数组
可以通过两种方式创建带类型校验的Action数组:
方式1:自动推导数组类型(推荐)
直接创建数组,TypeScript会自动推导每个元素的类型并完成校验:
const actionArray = [ {command: walk, args:{x: 10, speed: 1}}, {command: jump, args:{y: 20, speed: 2}}, {command: shoot, args:{type: "fire", duration: 5}} ]; add(...actionArray); // 正常工作,数组内每个元素都会被类型校验
方式2:显式声明数组类型
如果需要更严格的类型约束,可以声明数组为具体Action类型的联合数组:
const actionArray: Array<Action<typeof walk> | Action<typeof jump> | Action<typeof shoot>> = [ {command: walk, args:{x: 10, speed: 1}}, {command: jump, args:{y: 20, speed: 2}}, {command: shoot, args:{type: "fire", duration: 5}} ]; add(...actionArray);
也可以使用通用的Action数组类型:
type ActionArray = Array<Action<(args: any) => void>>; const actionArray: ActionArray = [ {command: walk, args:{x: 10, speed: 1}}, {command: jump, args:{y: 20, speed: 2}} ];
无论哪种方式,数组内的元素都会被TypeScript校验,确保args与对应command的参数类型匹配。
内容的提问来源于stack exchange,提问作者SomeRandomUserIGuess
相关产品推荐
相关产品推荐

