TypeScript中如何根据其他函数参数动态控制参数必选/可选状态
TypeScript 按参数值条件约束参数必传的实现方案
问题描述
需要实现函数类型校验:函数第三个参数trailer为可选参数,是否需要传入由参数vehicleType决定。将trailer设为可选参数后存在两个问题:
- 代码抛出类型错误
- 需要实现规则:
vehicleType取值为Pickup时强制传入trailer,取值为Car时无需传入trailer
问题复现代码
enum VehicleType { Car, Pickup } type Vehicle = { weight: number; length: number; }; type Trailer = { weight: number; length: number; }; function vehicle( vehicleType: VehicleType, vehicle: Vehicle, trailer?: Trailer ) { switch (vehicleType) { case VehicleType.Car: return `${vehicle.length} ${vehicle.weight}`; case VehicleType.Pickup: return `${vehicle.length + trailer.length} ${ vehicle.weight + trailer?.weight }`; } }
上述代码运行时,访问trailer属性会抛出两次相同报错:Object is possibly 'undefined',需要让编译器在vehicleType为Pickup时强制要求传入trailer参数,为Car时不做该要求。
实现方法
该需求可通过TypeScript的函数重载特性实现,这是处理条件参数场景的标准方案,可同时解决类型报错问题。
修正后代码
enum VehicleType { Car, Pickup } type Vehicle = { weight: number; length: number; }; type Trailer = { weight: number; length: number; }; // 重载签名1:传入Car类型时,不需要第三个trailer参数 function vehicle( vehicleType: VehicleType.Car, vehicle: Vehicle ): string; // 重载签名2:传入Pickup类型时,必须传第三个trailer参数 function vehicle( vehicleType: VehicleType.Pickup, vehicle: Vehicle, trailer: Trailer ): string; // 函数内部实现(对外不可见,仅用于兼容重载签名) function vehicle( vehicleType: VehicleType, vehicle: Vehicle, trailer?: Trailer ) { switch (vehicleType) { case VehicleType.Car: return `${vehicle.length} ${vehicle.weight}`; case VehicleType.Pickup: // 重载规则保证进入该分支时trailer必然存在,非空断言可消除undefined报错 return `${vehicle.length + trailer!.length} ${ vehicle.weight + trailer!.weight }`; } }
校验效果
- 合法调用:
vehicle(VehicleType.Car, { weight: 1200, length: 4.5 })校验通过vehicle(VehicleType.Pickup, { weight: 2000, length: 5.2 }, { weight: 600, length: 2.1 })校验通过
- 非法调用会直接抛出类型错误:
- 传入
VehicleType.Car时额外传trailer参数:报错提示Car类型不需要第三个参数 - 传入
VehicleType.Pickup时不传trailer参数:报错提示缺少第三个参数
- 传入
- 函数内部
Pickup分支下,TS可通过重载规则推导出trailer一定存在,不会再出现"Object is possibly 'undefined'"的提示,无需写可选链访问属性。
实现签名的参数需要兼容所有重载签名的参数类型,编写函数逻辑时可根据分支场景用非空断言收窄类型,也可补充运行时判断做兜底防护。
内容的提问来源于stack exchange,提问作者Hairi
相关产品推荐
相关产品推荐

