如何为多Payload类型的Switch Case参数添加TypeScript类型?
多Handler场景下的TypeScript Payload类型约束方案
场景代码
public async handle( handler: WorkflowHandlerOption, payload: <how_to_type_it?>, ): Promise<StepResponseInterface> { switch (handler) { case WorkflowHandlerOption.JOB_APPLICATION_ACTIVITY: { const { entity_id: jobApplicationEntityId, status: jobApplicationStatus, } = await this.jobApplicationActivityHandler.execute(payload); // ...other staff break; } case WorkflowHandlerOption.BILLING_FEE: { const { entity_id: billingFeeId, status: billingFeeStatus } = await this.billingFeeHandler.execute(payload); // ...other staff break; } case WorkflowHandlerOption.DOCUMENT_GENERATION: { const { entity_id: documentId, status: documentStatus } = await this.documentGenerationHandler.execute(payload); // ...other staff break; } case WorkflowHandlerOption.UPDATE_JOB: { const { entity_id: jobId, status: jobStatus } = await this.jobHandler.execute(payload); // ...other staff break; } case WorkflowHandlerOption.DOCUMENT_GENERATION_ACTIVITY: { const { entity_id: documentActivityId, status: documentActivityStatus, } = await this.documentGenerationActivityHandler.execute(payload); // ...other staff break; } default: throw new BadRequestException('Handler not found'); } // ...other staff }
需求说明
现有多个接收不同Payload的handler,需要为payload参数添加TypeScript类型定义,后续将扩展至近50个case场景,要求不依赖第三方库,仅通过TS原生类型实现。
解决方案
1. 定义各Handler对应的Payload类型
先为每个handler创建专属的Payload接口,明确字段结构:
// 示例Payload定义,根据实际业务字段调整 interface JobApplicationActivityPayload { applicantId: string; jobId: string; } interface BillingFeePayload { invoiceId: string; amount: number; } interface DocumentGenerationPayload { templateId: string; recipient: { name: string; email: string }; } interface UpdateJobPayload { jobId: string; status: 'open' | 'closed'; } interface DocumentGenerationActivityPayload { activityId: string; documentType: 'contract' | 'offer'; }
2. 创建Handler与Payload的映射关系
用TS的映射类型将WorkflowHandlerOption枚举值与对应Payload绑定,形成类型映射表:
type HandlerPayloadMap = { [WorkflowHandlerOption.JOB_APPLICATION_ACTIVITY]: JobApplicationActivityPayload; [WorkflowHandlerOption.BILLING_FEE]: BillingFeePayload; [WorkflowHandlerOption.DOCUMENT_GENERATION]: DocumentGenerationPayload; [WorkflowHandlerOption.UPDATE_JOB]: UpdateJobPayload; [WorkflowHandlerOption.DOCUMENT_GENERATION_ACTIVITY]: DocumentGenerationActivityPayload; };
3. 用泛型实现类型关联(适合大量扩展场景)
将handle方法改为泛型方法,让TS根据传入的handler自动推断payload的类型,无需写大量重载签名:
public async handle<T extends WorkflowHandlerOption>( handler: T, payload: HandlerPayloadMap[T] ): Promise<StepResponseInterface> { switch (handler) { case WorkflowHandlerOption.JOB_APPLICATION_ACTIVITY: { // 此时payload自动推断为JobApplicationActivityPayload类型 const { entity_id: jobApplicationEntityId, status: jobApplicationStatus } = await this.jobApplicationActivityHandler.execute(payload); // ...其他逻辑 break; } case WorkflowHandlerOption.BILLING_FEE: { // payload自动推断为BillingFeePayload类型 const { entity_id: billingFeeId, status: billingFeeStatus } = await this.billingFeeHandler.execute(payload); // ...其他逻辑 break; } // 其余case同理 case WorkflowHandlerOption.DOCUMENT_GENERATION: case WorkflowHandlerOption.UPDATE_JOB: case WorkflowHandlerOption.DOCUMENT_GENERATION_ACTIVITY: { // 对应类型会自动匹配 // ...逻辑 break; } default: throw new BadRequestException('Handler not found'); } // ...其他逻辑 }
4. 扩展新Handler的流程
后续新增handler时,只需完成3步:
- 新增对应Payload接口
- 在
HandlerPayloadMap中添加枚举值与Payload的映射关系 - 在switch中新增对应的case分支
TS会自动完成类型推断和校验,无需额外配置。
可选:用重载签名提升调用时的类型提示
如果希望调用handle方法时,IDE能更直观地展示每个handler对应的Payload结构,可以添加重载签名:
// 重载签名:为每个handler明确参数组合 public async handle(handler: WorkflowHandlerOption.JOB_APPLICATION_ACTIVITY, payload: JobApplicationActivityPayload): Promise<StepResponseInterface>; public async handle(handler: WorkflowHandlerOption.BILLING_FEE, payload: BillingFeePayload): Promise<StepResponseInterface>; public async handle(handler: WorkflowHandlerOption.DOCUMENT_GENERATION, payload: DocumentGenerationPayload): Promise<StepResponseInterface>; // 其余handler的重载签名... // 实现签名:复用泛型或联合类型 public async handle<T extends WorkflowHandlerOption>( handler: T, payload: HandlerPayloadMap[T] ): Promise<StepResponseInterface> { // 原switch逻辑 }
这种方式在调用时,选择不同的handler后,IDE会自动提示对应的Payload字段,但需要为每个新handler添加重载行,适合handler数量中等的场景;如果是50+的场景,泛型方式更简洁。
内容的提问来源于stack exchange,提问作者George Hutanu
相关产品推荐
相关产品推荐

