为何将typeof类型守卫赋值给变量后无法正常工作?
这是个超常见的TypeScript类型收窄问题,咱先把原因说清楚,再给你可行的解决办法~
问题本质:控制流分析的局限性
TypeScript的控制流分析(就是它根据代码逻辑推断变量类型的能力),只有在特定场景下才能识别类型守卫。当你把typeof variable === 'number'的结果存到独立的const is_number变量里时,TypeScript没法把这个布尔变量和原变量variable的类型绑定起来——它只知道is_number是个布尔值,但完全不知道这个值对应的是variable的哪种类型,所以在if (is_number)分支里,它还是认为variable是number | string,自然就会报类型不匹配的错误。
而直接在if条件里写typeof variable === 'number'时,TypeScript能立刻识别这是一个typeof类型守卫,会自动把variable的类型在if分支收窄成number,else分支收窄成string,所以不会报错。
解决办法:不用必须直接写typeof!
你有两种更优雅的方式来处理这个情况,不用非得把typeof写在条件里:
1. 自定义类型守卫函数(推荐)
写一个带类型谓词的函数,明确告诉TypeScript这个判断对应的变量类型:
// 自定义类型守卫,返回类型谓词 function isNumber(variable: number | string): variable is number { return typeof variable === 'number'; } function func(variable: number | string) { let variable2: number, variable3: string; if (isNumber(variable)) { variable2 = variable; // TypeScript现在知道variable是number啦 } else { variable3 = variable; // 这里自动收窄成string } }
这里的variable is number就是类型谓词,它告诉TypeScript:当这个函数返回true时,传入的variable一定是number类型。这样TypeScript的控制流分析就能正确关联类型,不会再报错。
2. 类型断言(应急方案,不推荐)
如果你非常确定当前分支里变量的类型,可以用as来强制断言类型:
function func(variable: number | string) { const is_number = (typeof variable === 'number'); let variable2: number, variable3: string; if (is_number) { variable2 = variable as number; } else { variable3 = variable as string; } }
⚠️ 注意:类型断言是你在“教TypeScript做事”,如果后续代码逻辑改变,比如判断条件写错了,很可能会导致运行时错误,所以除非万不得已,优先用自定义类型守卫。
总结
不是必须直接在条件里写typeof,只是你之前的写法没有让TypeScript识别到类型和判断逻辑的关联。用自定义类型守卫是既安全又可复用的方案,类型断言则是临时的应急手段~
内容的提问来源于stack exchange,提问作者left click

