You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript工厂类中联合类型参数与接口不兼容的报错问题

TypeScript工厂类类型不兼容问题解决

问题代码与报错

工厂类实现:

@Injectable()
export class JobApiFactoryService
  implements ApiServiceFactoryInterface<JobApiPayloads>
{
  public constructor(
    private readonly createApplicationActivityService: CreateApplicationActivityService,
    private readonly createActivityService: CreateActivityService
  ) {}

  public async execute(
    payload: JobApiPayloads,
    action: ApiNamesEnum
  ): Promise<void> {
    switch (action) {
      case ApiNamesEnum.CREATE_JOB_APPLICATION_ACTIVITY_EXTENSION:
        await this.createApplicationActivityService.execute(payload);
        break;
      case ApiNamesEnum.CREATE_JOB_ACTIVITY:
        await this.createActivityService.execute(payload);
        break;
      default:
        throw new Error("Invalid action");
    }
  }
}

Payload类型定义:

export type JobApiPayloads = JobApplicationActivityExtensionPayloadInterface |
  JobActivityExtensionInterface;

报错信息:

Argument of type 'JobApiPayloads' is not assignable to parameter of type 'JobApplicationActivityExtensionPayloadInterface'.   Type 'JobActivityExtensionInterface' is missing the following properties from type 'JobApplicationActivityExtensionPayloadInterface': jobId, candidate_ids

解决方案

方案1:类型断言(快速解决)

直接在调用服务时,将payload断言为对应方法所需的类型,让TypeScript明确当前分支的payload类型:

public async execute(
  payload: JobApiPayloads,
  action: ApiNamesEnum
): Promise<void> {
  switch (action) {
    case ApiNamesEnum.CREATE_JOB_APPLICATION_ACTIVITY_EXTENSION:
      await this.createApplicationActivityService.execute(
        payload as JobApplicationActivityExtensionPayloadInterface
      );
      break;
    case ApiNamesEnum.CREATE_JOB_ACTIVITY:
      await this.createActivityService.execute(
        payload as JobActivityExtensionInterface
      );
      break;
    default:
      throw new Error("Invalid action");
  }
}

说明:此方法简单直接,但依赖开发者保证action和payload的对应关系,运行时如果传错仍会出错。

方案2:类型守卫(更安全)

定义类型守卫函数,让TypeScript在分支中自动推断payload类型,避免手动断言的风险:

// 定义类型守卫函数
function isJobApplicationActivityPayload(
  payload: JobApiPayloads
): payload is JobApplicationActivityExtensionPayloadInterface {
  return 'jobId' in payload && 'candidate_ids' in payload;
}

function isJobActivityPayload(
  payload: JobApiPayloads
): payload is JobActivityExtensionInterface {
  // 根据JobActivityExtensionInterface的独有属性判断,示例假设它有activityId
  return 'activityId' in payload;
}

// 修改工厂类execute方法
public async execute(
  payload: JobApiPayloads,
  action: ApiNamesEnum
): Promise<void> {
  switch (action) {
    case ApiNamesEnum.CREATE_JOB_APPLICATION_ACTIVITY_EXTENSION:
      if (isJobApplicationActivityPayload(payload)) {
        await this.createApplicationActivityService.execute(payload);
      } else {
        throw new Error("Payload mismatch for action");
      }
      break;
    case ApiNamesEnum.CREATE_JOB_ACTIVITY:
      if (isJobActivityPayload(payload)) {
        await this.createActivityService.execute(payload);
      } else {
        throw new Error("Payload mismatch for action");
      }
      break;
    default:
      throw new Error("Invalid action");
  }
}

说明:类型守卫通过检查payload的独有属性,让TypeScript在if分支内确认payload类型,同时增加了运行时校验,比断言更安全。

方案3:关联Action与Payload类型(最严谨)

重构参数,让每个Action与对应的Payload类型强绑定,从根源避免类型不匹配:

// 定义Action与Payload的映射类型
type ApiActionMap = {
  [ApiNamesEnum.CREATE_JOB_APPLICATION_ACTIVITY_EXTENSION]: JobApplicationActivityExtensionPayloadInterface;
  [ApiNamesEnum.CREATE_JOB_ACTIVITY]: JobActivityExtensionInterface;
};

// 修改execute方法的参数类型
public async execute<Action extends keyof ApiActionMap>(
  payload: ApiActionMap[Action],
  action: Action
): Promise<void> {
  switch (action) {
    case ApiNamesEnum.CREATE_JOB_APPLICATION_ACTIVITY_EXTENSION:
      await this.createApplicationActivityService.execute(payload);
      break;
    case ApiNamesEnum.CREATE_JOB_ACTIVITY:
      await this.createActivityService.execute(payload);
      break;
    default:
      throw new Error("Invalid action");
  }
}

说明:此方法通过泛型和映射类型,强制action和payload的类型对应,调用时如果传错类型,TypeScript会直接在编译阶段报错,完全避免了类型不兼容问题。

内容的提问来源于stack exchange,提问作者George Hutanu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 20:30:57