有关 typescript 中 判断是否是 never 和 unknown 类型的解释

typescript 复制代码
export type IfNever<T, Y = true, N = false> = [T] extends [never] ? Y : Nexport type IfUnknown<T, Y, N> = [unknown] extends [T] ? Y : N

仔细看这两行代码,发现等号右边 [T] extends [never][unknown] extends [T]的 顺序为啥不一样?

[unknown] extends [T] 为什么不能写成 [T] extends [unkonw] ?

类型推导的方向性:

  • 在 TypeScript 的类型系统中,类型推导是从 "较宽泛的类型" 推导到 "较具体的类型"。
  • unknown 表示所有可能的类型,是所有类型中最宽泛的类型。
  • 当我们要检查一个类型 T 是否为 unknown 时,应该从 unknown 出发,推导它是否可以扩展到 T,而不是反过来。

[unknown] extends [T] 的含义:

  • 这表示 "一个元素类型为 unknown 的数组是否可以扩展(assignable)到一个元素类型为 T 的数组"。
  • 如果 Tunknown,那么 unknown 可以扩展到 unknown 本身,条件为真,返回 Y
  • 如果 T 是其他具体类型,比如 stringnumber 等,那么 unknown 无法扩展到这些类型,条件为假,返回 N

为什么不写成 [T] extends [unknown]

  • 虽然从语法上可以这么写,但这会导致类型推导逻辑的错误。
  • 因为 unknown 可以扩展到所有类型,所以 [unknown] 可以扩展到 [T],无论 T 是什么类型。
  • 这会导致条件永远为真,始终返回 Y,无法判断 T 是否为 unknown

实际应用:

IfUnknown 类型通常用于在条件类型中处理 unknown 类型,例如:

TypeScript

r 复制代码
type SafeProp<T> = IfUnknown<T, never, T>; // 如果 T 是 unknown,返回 never,否则返回 T

function handleProp<T>(prop: SafeProp<T>) {
  // 在这里可以安全地处理 prop,因为它不可能是 unknown
}

这样可以确保在函数内部,prop 的类型一定不是 unknown,可以进行安全的操作,避免潜在的类型错误。

总结:

export type IfUnknown<T, Y, N> = [unknown] extends [T] ? Y : N 的写法更符合类型推导的逻辑,可以正确判断一个类型是否为 unknown,并在条件类型中提供更精确的类型控制。

[T] extends [never] 为什么不能写成 [never] extends [T] ?

我会解释 export type IfNever<T, Y = true, N = false> = [T] extends [never] ? Y : N 的作用以及它在类型系统中的含义:

1. 类型推导与 never 类型:

  • 在 TypeScript 中,never 类型表示永远不会存在的值。它是所有类型的子类型,但没有任何值属于 never 类型。
  • 当使用类型推导来检查一个类型是否为 never 时,需要从 never 类型出发,推导它是否可以扩展到该类型。

2. 条件类型的逻辑:

  • IfNever<T, Y = true, N = false> = [T] extends [never] ? Y : N 定义了一个条件类型。
  • 它的意思是:如果 T 可以扩展到 never 类型,那么返回 Y,否则返回 N

3. 为什么 [T] extends [never] 而不是 [never] extends [T]:

  • 因为 never 是所有类型的子类型,所以 [never] 可以扩展到任何类型的数组 [T],无论 T 是什么类型。
  • 因此,如果写成 [never] extends [T],条件永远为真,无法判断 T 是否为 never

4. 实际用途:

  • 在类型系统中,IfNever<T> 常用于以下场景:

    • 检查一个类型是否为 never,例如:

      r 复制代码
      type IsNever<T> = IfNever<T>;
    • 在条件类型中排除 never 类型,例如:

      TypeScript

      r 复制代码
      type NonNever<T> = IfNever<T, never, T>; // 如果 T 是 never,返回 never,否则返回 T
    • 在泛型函数中处理 never 类型,例如:

      TypeScript

      r 复制代码
      function handleValue<T>(value: T): IfNever<T, void, T> {
        // 如果 T 是 never,则不返回任何值
        // 否则返回 value
      }

总结:

IfNever 类型是 TypeScript 中的一个有用的条件类型,用于判断一个类型是否为 never,并在类型系统中提供更灵活的类型控制。

以上问题衍生出来两个疑问:

所有类型都是 unkonwn 的子类型吗?

在 TypeScript 中,unknown 表示所有可能的类型,是所有类型中最宽泛的类型。因此,所有类型都是 unknown 的子类型

从类型推导的角度来看,unknown 可以扩展到所有类型 。因此,T 可以扩展到 unknown,无论 T 是什么类型。

从类型安全的角度来看,unknown 可以表示任何类型的值,包括未知的值。因此,将 unknown 赋值给其他类型的变量是安全的

以下是一些例子:

typescript 复制代码
// 所有类型都是 `unknown` 的子类型
let a: number = 1;
let b: unknown = a; // 合法

// `unknown` 可以扩展到所有类型
let c: unknown = 'hello';
let d: string = c; // 合法

// 将 `unknown` 赋值给其他类型的变量是安全的
let e: never = undefined;
let f: unknown = e; // 合法

never 是所有类型的 子类型吗?

在 TypeScript 中,never 表示永远不会存在的值。因此,never 不是任何类型的子类型。(你可以这样认为,但这是错误的说法)

从类型推导的角度来看,never 不能扩展到任何类型 。因此,never 不能扩展到 T,无论 T 是什么类型。

从类型安全的角度来看,never 表示永远不会存在的值。因此,将 never 赋值给其他类型的变量是不可能的

以下是一些例子:

typescript 复制代码
// `never` 不是任何类型的子类型
let a: number = 1;
let b: never = a; // 不合法

// `never` 不能扩展到任何类型
let c: unknown = 'hello';
let d: never = c; // 不合法

// 将 `never` 赋值给其他类型的变量是不可能的
let e: string = undefined;
let f: never = e; // 不合法

需要注意的是,never 类型的值永远不会存在,因此无法使用。

相关推荐
酒尘&8 小时前
JS数组不止Array!索引集合类全面解析
开发语言·前端·javascript·学习·js
学历真的很重要8 小时前
VsCode+Roo Code+Gemini 2.5 Pro+Gemini Balance AI辅助编程环境搭建(理论上通过多个Api Key负载均衡达到无限免费Gemini 2.5 Pro)
前端·人工智能·vscode·后端·语言模型·负载均衡·ai编程
用户47949283569159 小时前
"讲讲原型链" —— 面试官最爱问的 JavaScript 基础
前端·javascript·面试
用户47949283569159 小时前
2025 年 TC39 都在忙什么?Import Bytes、Iterator Chunking 来了
前端·javascript·面试
大怪v10 小时前
【Virtual World 04】我们的目标,无限宇宙!!
前端·javascript·代码规范
狂炫冰美式10 小时前
不谈技术,搞点文化 🧀 —— 从复活一句明代残诗破局产品迭代
前端·人工智能·后端
xw511 小时前
npm几个实用命令
前端·npm
!win !11 小时前
npm几个实用命令
前端·npm
代码狂想家11 小时前
使用openEuler从零构建用户管理系统Web应用平台
前端
dorisrv13 小时前
优雅的React表单状态管理
前端