‘not null’类型守卫else分支解析为never,如何改为null?
解决TypeScript类型守卫else分支推断为never的问题
你写的这个isNotNull类型守卫本身逻辑是没问题的,之所以else分支会被推断成never,是因为你的测试用例里的运行时值干扰了TypeScript的控制流分析。
先拆解下问题:
你的类型守卫代码:
function isNotNull<T> (arg: T): arg is Exclude<T, null> { return arg !== null }
这段代码完全正确——它告诉TS:如果函数返回true,参数就是T去掉null后的类型;按道理,当T是string | null时,else分支应该被推断为null才对。
那为什么你的测试代码里else分支是never?看你给value赋值的代码:
const value: string | null = 0 as any
虽然你把value的类型标注成了string | null,但运行时它实际是0,而0 !== null永远为true,所以这个else分支根本不可能被执行到。TS的控制流分析能识别这种不可达分支,直接把分支里的value类型推断成never了。
怎么让else分支类型变成null?
很简单,只要让value真的有可能是null就行:
1. 用符合类型定义的测试数据
比如让value随机取string或null,确保两个分支都有执行的可能:
const value: string | null = Math.random() > 0.5 ? "typescript" : null; if (isNotNull(value)) { // 这里value类型是string,放心调用字符串方法 console.log(value.toUpperCase()); } else { // 这里value类型就是null啦 console.log("value is null"); }
2. 换一种更直观的类型守卫写法(可选)
如果你想让反向推断更一目了然,也可以写一个专门判断null的类型守卫,效果是一样的:
function isNull<T>(arg: T): arg is Extract<T, null> { return arg === null; } // 使用示例 const value: string | null = Math.random() > 0.5 ? "typescript" : null; if (isNull(value)) { // value类型:null } else { // value类型:string }
这样不管正向还是反向分支,类型推断都完全符合你的预期啦。
内容的提问来源于stack exchange,提问作者Lazar Ljubenović
相关产品推荐
相关产品推荐

