never 类型

never 类型表示永不存在的值,常用于表示不会正常返回的函数或不可能发生的类型。

基本概念

never 是所有类型的子类型,但没有类型是 never 的子类型(除了 never 本身)。

函数永不返回

抛出异常

function throwError(message: string): never {
  throw new Error(message)
}

throwError("出错了")  // 后续代码不会执行

无限循环

function infiniteLoop(): never {
  while (true) {
    // 永不退出
  }
}

类型收窄

never 用于表示不可能的分支:

function process(value: string | number): void {
  if (typeof value === "string") {
    console.log(value.toUpperCase())
  } else if (typeof value === "number") {
    console.log(value.toFixed(2))
  } else {
    const _exhaustive: never = value  // 确保所有情况都被处理
  }
}

穷尽检查

确保处理了所有可能的情况:

enum Color {
  Red,
  Green,
  Blue
}

function getColorName(color: Color): string {
  switch (color) {
    case Color.Red:
      return "红色"
    case Color.Green:
      return "绿色"
    case Color.Blue:
      return "蓝色"
    default:
      const _exhaustive: never = color
      throw new Error(`未知的颜色: ${color}`)
  }
}

如果添加新的枚举值,default 分支会报错:

enum Color {
  Red,
  Green,
  Blue,
  Yellow  // 新增
}

// default 分支会报错:Type Color.Yellow is not assignable to type 'never'

类型推断

TypeScript 会自动推断 never 类型:

function fail(message: string): never {
  throw new Error(message)
}

function infinite(): never {
  while (true) {}
}

// 变量推断
let value: string | number

if (typeof value === "string") {
  // value: string
} else if (typeof value === "number") {
  // value: number
} else {
  // value: never
}

实际应用

断言函数

function assertNever(value: never): never {
  throw new Error(`未处理的值: ${value}`)
}

type Shape = { kind: "circle"; radius: number } | { kind: "square"; size: number }

function getArea(shape: Shape): number {
  switch (shape.kind) {
    case "circle":
      return Math.PI * shape.radius ** 2
    case "square":
      return shape.size ** 2
    default:
      return assertNever(shape)
  }
}

不可达代码检测

function process(value: "a" | "b"): string {
  if (value === "a") {
    return "A"
  }
  if (value === "b") {
    return "B"
  }
  // 这里 value 类型是 never
  value  // 永远不会执行
}

类型工具

type Exclude<T, U> = T extends U ? never : T

type Result = Exclude<"a" | "b" | "c", "a">  // "b" | "c"

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never

function fn(): string {
  return "hello"
}

type FnReturn = ReturnType<typeof fn>  // string

不可能的交叉

type StringAndNumber = string & number  // never

let value: StringAndNumber  // 永远无法赋值

never vs void

类型说明
void函数正常结束,没有返回值
never函数永不返回
function log(message: string): void {
  console.log(message)
}

function fail(message: string): never {
  throw new Error(message)
}

数组过滤

type NonNullable<T> = T extends null | undefined ? never : T

type Result = NonNullable<string | null | undefined>  // string

// 过滤数组中的 null 和 undefined
function filterNonNull<T>(arr: (T | null | undefined)[]): T[] {
  return arr.filter((item): item is T => item !== null && item !== undefined)
}

const items = [1, null, 2, undefined, 3]
const filtered = filterNonNull(items)  // [1, 2, 3]

注意事项

never 的赋值

let n: never

n = 1        // 错误
n = "hello"  // 错误
n = null     // 错误
n = undefined  // 错误

// 只有 never 可以赋值给 never
function fn(): never {
  throw new Error("")
}
n = fn()  // 正确

函数返回推断

function fn() {
  throw new Error("")
}

// 返回类型推断为 never

联合类型中的 never

type Result = string | never  // string

// never 在联合类型中会被忽略

交叉类型中的 never

type Result = string & never  // never

// 任何类型与 never 交叉都是 never