You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
}

代码说明

  1. 泛型:接收输入值的原始类型,让类型守卫能基于具体类型做精准判断。
  2. 条件类型:
    • Extract<T, null | undefined | '' | 0 | typeof NaN>:提取T中属于基础空值的类型
    • (T extends any[] ? [] : never):如果T是数组类型,则匹配空数组[]
    • (T extends object ? {} : never):如果T是对象类型,则匹配空对象{}
  3. 逻辑对齐:函数内部的判断逻辑和类型守卫的条件完全一致,确保类型推断的准确性。

测试验证

现在再运行之前的测试代码,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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 11:20:28