返回联合类型引发TypeScript类型校验报错,如何解决?
解决TypeScript联合类型属性访问报错的问题
这个问题是TypeScript里联合类型的常见场景——当你拿到一个可能是两种不同类型的值时,TypeScript没办法确定当前到底是哪一种,所以直接访问某一个类型独有的属性就会报错,就像你遇到的code属性不存在于IMakes的提示。
下面给你几种实用的解决办法:
1. 用in操作符做类型守卫
这是最简单的方式,不需要额外写函数,直接检查目标属性是否存在,TypeScript会自动推断类型:
getCarMakes(2024).then(data => { if ('code' in data) { // 这里TypeScript明确知道data是IErrorResponse类型 console.error(`请求失败:${data.code} - ${data.msg}`); } else { // 这里自动推断为IMakes类型 console.log('可用车型品牌:', data.makes); } });
2. 自定义类型谓词函数
如果需要更复杂的判断逻辑,或者想把类型检查逻辑复用,可以写一个自定义的类型守卫函数:
// 定义一个类型谓词,告诉TypeScript如果函数返回true,参数就是IErrorResponse function isErrorResponse(res: IMakes | IErrorResponse): res is IErrorResponse { // 检查code属性是否存在且是数字类型(可选,更严谨) return typeof (res as IErrorResponse).code === 'number'; } // 使用的时候 getCarMakes(2024).then(data => { if (isErrorResponse(data)) { console.error(`错误码:${data.code},消息:${data.msg}`); } else { console.log(data.makes); } });
3. 进阶:改用区分联合类型(Discriminated Union)
如果API允许调整返回格式,或者返回结果里本来就有一个用来区分成功/失败的字段(比如type或status),推荐把接口改成区分联合类型,这是TypeScript处理这类场景最清晰的方式:
// 修改接口,添加一个共同的区分字段 interface IMakes { type: 'success'; // 成功响应的标识 makes: string[]; } interface IErrorResponse { type: 'error'; // 错误响应的标识 code: number; msg: string; } // 调用时用switch判断类型 getCarMakes(2024).then(data => { switch (data.type) { case 'error': console.error(`请求出错:${data.code} - ${data.msg}`); break; case 'success': console.log('车型列表:', data.makes); break; } });
这种方式下,TypeScript会根据type字段精准推断类型,完全不会有属性访问的报错,代码可读性也更高。
额外优化:统一函数返回值
另外注意你原来的函数里,catch块是直接throw new Error(error),这会让函数的返回值变成Promise<IMakes | IErrorResponse> | Promise<never>(因为抛出错误会终止Promise链)。如果想让函数始终返回Promise<IMakes | IErrorResponse>,可以把错误转换成IErrorResponse对象返回:
export const getCarMakes = (year: number): Promise<IMakes | IErrorResponse> => { return fetch('url', { method: 'GET' }) .then((res: Response) => res.json()) .then((data: IMakes | IErrorResponse) => data) .catch((error: any) => { // 将捕获的错误转换成IErrorResponse格式返回 return { code: 500, msg: error.message || '请求失败' } as IErrorResponse; }); };
这样调用方只需要处理返回的联合类型,不用额外处理Promise的reject状态,更符合你最初定义的函数返回类型。
内容的提问来源于stack exchange,提问作者MarJano
相关产品推荐
相关产品推荐

