TypeScript空值判断方法的返回类型与never类型报错问题
解决TypeScript中isNullOrUndefinedOrEmpty类型守卫的"never"类型错误
问题背景
我需要编写一个TypeScript方法,用来检测值是否为null、undefined、''、[]、{}或0,并设置对应的返回类型。当前实现的方法如下:
/** * Return true if value is a "empty" val, eg: null, undefined, '', [], {}, 0 */ export const isNullOrUndefinedOrEmpty = (value: any): value is null | undefined | '' | [] | {} | 0 => { if (value === null || value === undefined || value === '' || value === 0) { return true; } if (typeof value === 'number' && isNaN(value)) { return true; } if (typeof value === 'object') { if (Array.isArray(value)) { return value.length <= 0; } else { return Object.keys(value).length === 0 && value.constructor === Object; } } return false; };
但在以下使用场景中,TypeScript会报错Property 'a' does not exist on type 'never':
const testEmpty = {}; if( !isNullOrUndefinedOrEmpty(testEmpty) ){ alert(testEmpty.a) } const testNotEmpty = {a: true}; if( !isNullOrUndefinedOrEmpty(testNotEmpty) ){ alert(testNotEmpty.a) }
错误原因
当前的类型守卫返回value is null | undefined | '' | [] | {} | 0,当取反!isNullOrUndefinedOrEmpty(xxx)时,TypeScript会尝试从原始类型中排除这些空类型。但{}是所有非空对象的超类型,排除空类型后,TypeScript无法推断出剩余类型的具体结构,只能将其判定为never,导致访问属性时触发错误。
解决方案
我们需要通过泛型+条件类型优化类型守卫,让它能精准区分空值和非空值,同时保留输入值的原始类型信息。
修正后的代码
/** * Return true if value is a "empty" val, eg: null, undefined, '', [], {}, 0, NaN */ export function isNullOrUndefinedOrEmpty<T>(value: T): value is Extract<T, null | undefined | '' | 0 | typeof NaN> | (T extends any[] ? [] : never) | (T extends object ? {} : never) { if (value === null || value === undefined || value === '' || value === 0) { return true; } if (typeof value === 'number' && isNaN(value)) { return true; } if (typeof value === 'object') { if (Array.isArray(value)) { return value.length === 0; } // 确保是普通空对象而非其他类实例 return Object.keys(value).length === 0 && value.constructor === Object; } return false; }
代码说明
- 泛型
:接收输入值的原始类型,让类型守卫能基于具体类型做精准判断。 - 条件类型:
Extract<T, null | undefined | '' | 0 | typeof NaN>:提取T中属于基础空值的类型(T extends any[] ? [] : never):如果T是数组类型,则匹配空数组[](T extends object ? {} : never):如果T是对象类型,则匹配空对象{}
- 逻辑对齐:函数内部的判断逻辑和类型守卫的条件完全一致,确保类型推断的准确性。
测试验证
现在再运行之前的测试代码,TypeScript能正确推断类型,不会再报never错误:
const testEmpty = {}; if (!isNullOrUndefinedOrEmpty(testEmpty)) { alert(testEmpty.a); // 这里testEmpty被推断为非空对象,不会报错 } const testNotEmpty = {a: true}; if (!isNullOrUndefinedOrEmpty(testNotEmpty)) { alert(testNotEmpty.a); // 正确识别testNotEmpty的类型为{a: boolean} }
内容的提问来源于stack exchange,提问作者ar099968
相关产品推荐
相关产品推荐

