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
相关产品推荐
相关产品推荐

