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

TypeScript类型映射中空对象类型检测及转换为void类型的实现问题问询

如何在TypeScript中检测空对象类型并映射为void

这个问题确实是TypeScript类型系统里的一个常见坑——你遇到的问题核心在于{}在TS中的行为和我们直觉里的“空对象”完全不同:几乎所有非null/undefined的类型都能extends {},包括字符串、数字这些原始类型(因为它们有对应的包装对象),更别说所有对象类型了,所以你的第一个写法会把绝大多数类型都映射成void,显然不符合预期。

而第二个写法T extends { any: any }确实只会匹配带有any属性的对象,完全没法覆盖“任意非空对象”的场景。

正确实现方案

要准确检测“空对象类型”,我们需要结合object类型判断和keyof操作符——空对象类型的核心特征是没有任何已知的属性键,也就是keyof T等于never。同时我们还要可以选择排除object这个通用对象类型(如果你希望它不被视为空对象的话)。

基础版本(包含object类型)

这个版本会把{}、Record<never, never>以及object类型都视为空对象:

// 辅助类型:判断是否为空对象
type IsEmptyObject<T> = 
  // 先过滤出对象类型(排除原始类型、null、undefined)
  T extends object 
    ? // 检查对象是否没有任何已知属性键
      keyof T extends never 
        ? true 
        : false 
    : false;

// 最终类型工具:空对象映射为void,否则保留原类型
type NotEmpty<T> = IsEmptyObject<T> extends true ? void : T;

严格版本(排除object类型)

如果你希望object这个通用类型不被映射为void,可以调整辅助类型,额外排除object本身:

type IsStrictEmptyObject<T> = 
  T extends object 
    ? // 确保是{}的子类型、无已知属性,且不是object本身
      (T extends {} ? keyof T extends never ? object extends T ? false : true : false : false)
    : false;

type NotEmpty<T> = IsStrictEmptyObject<T> extends true ? void : T;

测试用例验证

我们可以用几个例子验证效果:

// 基础版本测试
type Test1 = NotEmpty<{}>; // void ✔️
type Test2 = NotEmpty<Record<never, never>>; // void ✔️
type Test3 = NotEmpty<{a: number}>; // {a: number} ✔️
type Test4 = NotEmpty<string>; // string ✔️
type Test5 = NotEmpty<null>; // null ✔️
type Test6 = NotEmpty<object>; // void(基础版本)/ object(严格版本) ✔️

原理说明

  1. T extends object:先过滤掉原始类型、null和undefined,只处理对象类型。
  2. keyof T extends never:判断该对象类型是否没有任何已知的属性键——空对象类型的keyof结果就是never,而非空对象(比如{a: number})的keyof会返回它的属性名联合类型。
  3. object extends T:在严格版本中,这个判断用来排除object类型本身——因为object是所有对象的父类,object extends T只有当T是object时才会返回true,这样就能把它从“空对象”的判断中排除。

内容的提问来源于stack exchange,提问作者lokimidgard

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 09:17:35