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

TypeScript联合类型类型守卫:消除IDE属性不存在报错

解决TypeScript联合类型的类型守卫问题

我编写了如下TypeScript函数:

export const createHousehold = async (data: HouseholdFormData): Promise<HouseholdDto | ErrorDto>  => {
  const response: HouseholdDto | ErrorDto = await householdService.createHousehold(data);
  revalidateTag('households');
 
  if (response.error) {
    const errorDto: ErrorDto = {
      status: response.status,
      message: response.message,
      error: response.error,
    };
    return errorDto;
  }
  return response;
};

对应的类型定义:

type HouseholdDto = {
  id: string,
  createdDate: Date,
  modifiedDate: Date,
  name: string,
}

type ErrorDto = {
  status: number,
  error: string,
  message: string,
}

当通过if (response.error)判断响应是否为ErrorDto类型时,IDE会提示response.error、response.status等属性不存在的报错。已知这是联合类型HouseholdDto | ErrorDto导致TS无法确定具体类型,希望通过类型守卫让IDE识别当前类型,且不想使用交叉类型HouseholdDto & ErrorDto,该如何解决?


方法一:使用in操作符进行类型缩小

TS原生支持通过in操作符检查对象是否包含某个属性,以此自动缩小联合类型的范围。因为ErrorDto包含error属性,而HouseholdDto没有,直接用这个条件就能让TS识别类型:

修改后的函数代码:

export const createHousehold = async (data: HouseholdFormData): Promise<HouseholdDto | ErrorDto>  => {
  const response: HouseholdDto | ErrorDto = await householdService.createHousehold(data);
  revalidateTag('households');
 
  if ('error' in response) {
    // 此时TS已确定response是ErrorDto类型
    const errorDto: ErrorDto = {
      status: response.status,
      message: response.message,
      error: response.error,
    };
    return errorDto;
  }
  // 此时TS已确定response是HouseholdDto类型
  return response;
};

方法二:自定义类型守卫函数

如果需要更复杂的类型校验逻辑,可以编写自定义类型守卫函数,通过类型谓词明确告诉TS当前对象的具体类型:

首先定义类型守卫函数:

function isErrorDto(obj: unknown): obj is ErrorDto {
  return typeof obj === 'object' && obj !== null 
    && 'error' in obj && 'status' in obj && 'message' in obj;
}

然后在业务函数中使用该守卫:

export const createHousehold = async (data: HouseholdFormData): Promise<HouseholdDto | ErrorDto>  => {
  const response: HouseholdDto | ErrorDto = await householdService.createHousehold(data);
  revalidateTag('households');
 
  if (isErrorDto(response)) {
    // TS已识别response为ErrorDto类型
    const errorDto: ErrorDto = {
      status: response.status,
      message: response.message,
      error: response.error,
    };
    return errorDto;
  }
  return response;
};

拓展:利用可选属性区分(不推荐)

如果允许修改原有类型定义,可以给HouseholdDto添加明确的可选error属性并设为undefined,让TS通过属性值判断类型,但这种方式需要改动类型结构,不符合你的需求,仅作参考:

type HouseholdDto = {
  id: string,
  createdDate: Date,
  modifiedDate: Date,
  name: string,
  error?: undefined, // 明确标记error不存在
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 22:58:32