TypeScript数字属性区分联合类型:如何实现正确类型推断?
解决TypeScript中联合类型的自动推断问题
核心方案:使用判别式联合类型(Discriminated Union)
TypeScript无法自动推断类型的根本原因是:你的两个类型(StatvfsInfo和StatvfsError)的errno属性都是普通number类型,没有明确的判别标识。解决的关键是给成功类型的errno指定字面量类型0,让TypeScript能通过这个固定值来缩小类型范围。
步骤1:定义判别式联合类型
// 错误类型:errno 为非0的数字 type StatvfsError = { errno: Exclude<number, 0>; }; // 成功类型:errno 固定为字面量0,附带扩展属性 type StatvfsInfo = { errno: 0; f_blocks: number; // 其他你需要的扩展属性,比如 f_bfree、f_bavail 等 }; // 联合类型:函数返回值只能是这两种类型之一 type StatvfsResult = StatvfsInfo | StatvfsError;
步骤2:实现返回该联合类型的函数
function getStatvfs(path: string): StatvfsResult { // 模拟实际逻辑:比如调用原生API后返回对应结果 try { // 假设成功获取到信息 return { errno: 0, f_blocks: 1048576, f_bfree: 524288 }; } catch (err) { // 失败时返回错误信息 return { errno: -1 // 非0的错误码 }; } }
步骤3:调用时自动推断类型
此时通过result.errno === 0判断后,TypeScript会自动将result的类型缩小为StatvfsInfo,访问扩展属性不会报错:
const result = getStatvfs('/'); if (result.errno === 0) { // 这里TypeScript明确知道result是StatvfsInfo console.log(`总块数:${result.f_blocks}`); console.log(`剩余块数:${result.f_bfree}`); } else { // 这里自动推断为StatvfsError console.log(`获取失败,错误码:${result.errno}`); }
兼容原有类型的方案:自定义类型守卫
如果无法修改已有的StatvfsInfo和StatvfsError类型定义(比如StatvfsInfo的errno已经是number类型),可以通过自定义类型守卫函数来手动告诉TypeScript如何区分类型:
步骤1:保留原有类型定义
// 原有类型:errno为number type StatvfsInfo = { errno: number; f_blocks: number; // 其他扩展属性 }; type StatvfsError = { errno: number; }; type StatvfsResult = StatvfsInfo | StatvfsError;
步骤2:编写类型守卫函数
// 自定义类型守卫,判断是否为StatvfsInfo function isStatvfsInfo(result: StatvfsResult): result is StatvfsInfo { // 同时判断errno为0,且包含扩展属性(避免误判) return result.errno === 0 && 'f_blocks' in result; }
步骤3:调用时使用类型守卫
const result = getStatvfs('/'); if (isStatvfsInfo(result)) { // TypeScript自动推断为StatvfsInfo console.log(result.f_blocks); } else { // 推断为StatvfsError console.log(`错误码:${result.errno}`); }
内容的提问来源于stack exchange,提问作者user7401478
相关产品推荐
相关产品推荐

