TypeScript使用Array.includes(null)后仍提示变量可能为null的问题
问题场景
我写了一段多变量null检查的代码:
const path = window.location.pathname const regex_list = path.match(/\d+/g) // 100% 至少包含一个数字 const a = document.querySelector('') const b = document.querySelector('') if (![regex_list, a, b].includes(null)) { regex_list[0] }
TypeScript抛出错误:
'regex_list' is possibly 'null'. (tsserver 18047)
哪怕只单独检查regex_list:
if (![regex_list].includes(null)) { regex_list[0] }
regex_list的类型是:
const regex_list: RegExpExecArray | null
我确定只要regex_list不为null就肯定是RegExpExecArray,但TypeScript不认可这个判断。想问:
- 是不是因为TypeScript只支持
==/!=/===/!==这类运算符做类型窄化? - 如果是这样,我能不能安全用
// @ts-ignore或者regex_list![0]忽略这个错误?
更新:我发现可以用类型断言(regex_list as RegExpExecArray)来窄化类型,但每次引用都要重复写,有点麻烦。
解答
为什么includes检查无法触发类型窄化
没错,TypeScript的类型窄化逻辑对数组的includes方法没有做特殊处理,它仅能识别直接使用===/!==等相等运算符的条件判断,或者typeof、instanceof、Array.isArray()这类内置类型守卫逻辑。
当你把变量放进数组再用includes(null)判断时,TS无法将数组的检查结果关联回原变量的类型状态,自然不会把regex_list的类型从RegExpExecArray | null窄化为RegExpExecArray。
能不能用@ts-ignore或非空断言
如果你能100%保证regex_list不会是null(比如你确认路径里一定有数字),那么用regex_list![0]非空断言是安全的,比// @ts-ignore更优——因为@ts-ignore会忽略该行所有TS错误,而非空断言只是明确告诉TS“这个变量不可能为null/undefined”,针对性更强。
但要注意:如果后续逻辑改动导致regex_list可能为null,非空断言会直接跳过TS检查,运行时可能报错,所以要确保你的前置条件不会变动。
更高效的类型窄化方案
如果不想每次都写类型断言,可以用以下方式一次性完成类型窄化:
- 自定义类型守卫函数:
function isNotNull<T>(val: T | null): val is T { return val !== null; } if (isNotNull(regex_list) && isNotNull(a) && isNotNull(b)) { regex_list[0]; // 这里类型已被窄化为RegExpExecArray }
- 初始化时直接断言:
const path = window.location.pathname; // 直接断言,因为你确定不会为null const regex_list = path.match(/\d+/g) as RegExpExecArray; const a = document.querySelector('') as HTMLElement; const b = document.querySelector('') as HTMLElement; // 后续无需再检查 regex_list[0];
- 可选链+空合并(允许默认值时):
const firstNum = regex_list?.[0] ?? 'default';
内容的提问来源于stack exchange,提问作者Andrew15_5

