TypeScript中基于字符串实现类型条件参数的开发问题咨询
实现方案
1. 定义动作与Payload的类型映射
这是实现动态类型推导的基础,先明确每个动作对应的入参要求:
// 定义可用的更新动作枚举 enum TRANSFER_AVAILABLE_UPDATE_ACTIONS { CANCEL = 'cancel', HOLD = 'hold' } // 定义Cancel动作对应的Payload类型 interface CancelPayload { admin_id: number } // 定义Hold动作对应的Payload类型 interface HoldPayload { duration: string } // 建立动作到对应Payload的映射关系 interface TransferUpdateActions { [TRANSFER_AVAILABLE_UPDATE_ACTIONS.CANCEL]: CancelPayload [TRANSFER_AVAILABLE_UPDATE_ACTIONS.HOLD]: HoldPayload }
2. 改造executeUpdateAction方法实现动态类型推导
给泛型增加类型约束,即可实现传入动作后自动推导Payload类型:
// 泛型K约束为TransferUpdateActions的键,即只能是已定义的动作 async executeUpdateAction<K extends keyof TransferUpdateActions>( action_type: K, action_payload: TransferUpdateActions[K], ) { if (action_type === TRANSFER_AVAILABLE_UPDATE_ACTIONS.CANCEL) { // TS会自动收窄action_payload为CancelPayload类型,无需额外断言 return this.cancelTransfer(action_payload); } if (action_type === TRANSFER_AVAILABLE_UPDATE_ACTIONS.HOLD) { // TS自动收窄为HoldPayload类型 return this.holdTransfer(action_payload); } // 其余动作逻辑 }
此时调用该方法时,只要传入第一个动作参数,第二个Payload参数会自动关联对应类型,获得完整的类型补全提示。
3. 改造update包装方法实现类型安全
先定义所有合法Payload的联合类型,再通过属性判断匹配对应动作即可:
// 定义所有合法的Payload联合类型,匹配任意一种动作的入参要求即可 type ValidUpdatePayload = TransferUpdateActions[keyof TransferUpdateActions] update(payload: ValidUpdatePayload) { // 匹配Cancel动作入参 if ('admin_id' in payload) { return this.executeUpdateAction(TRANSFER_AVAILABLE_UPDATE_ACTIONS.CANCEL, payload) } // 匹配Hold动作入参 if ('duration' in payload) { return this.executeUpdateAction(TRANSFER_AVAILABLE_UPDATE_ACTIONS.HOLD, payload) } throw new Error('不符合任何动作的入参要求') }
效果验证
- 调用
executeUpdateAction('hold', {duration: '1h'}):类型校验通过,有完整的参数补全提示 - 调用
executeUpdateAction('hold', {admin_id: 123}):TS直接抛出类型不匹配错误 - 调用
update({admin_id: 123}):校验通过 - 调用
update({duration: '2h'}):校验通过 - 调用
update({unknown_field: 'xxx'}):TS抛出类型错误,拒绝不符合要求的入参
可选优化:如果需要严格限制Payload不能包含多余属性,可以给每个Payload类型增加唯一的可辨识字段(比如action_type),做成可辨识联合,类型校验会更严谨。
内容的提问来源于stack exchange,提问作者paul.kim1901
相关产品推荐
相关产品推荐

