有关 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 类型的值永远不会存在,因此无法使用。

相关推荐
GISer_Jing5 分钟前
前端面试常考题目详解
前端·javascript
Boilermaker19921 小时前
【Java EE】SpringIoC
前端·数据库·spring
中微子1 小时前
JavaScript 防抖与节流:从原理到实践的完整指南
前端·javascript
天天向上10241 小时前
Vue 配置打包后可编辑的变量
前端·javascript·vue.js
芬兰y2 小时前
VUE 带有搜索功能的穿梭框(简单demo)
前端·javascript·vue.js
好果不榨汁2 小时前
qiankun 路由选择不同模式如何书写不同的配置
前端·vue.js
小蜜蜂dry2 小时前
Fetch 笔记
前端·javascript
拾光拾趣录2 小时前
列表分页中的快速翻页竞态问题
前端·javascript
小old弟2 小时前
vue3,你看setup设计详解,也是个人才
前端
Lefan2 小时前
一文了解什么是Dart
前端·flutter·dart