TypeScript never 类型详解
什么是 never 类型?
never 是 TypeScript 中的一种特殊类型,表示永远不会发生的值的类型。它通常用于以下场景:
- 函数永远不会正常返回(抛出错误或无限循环)
 - 类型系统中表示不可能的情况
 - 类型保护中的详尽性检查
 
基本语法和用法
1. 永远不会返回的函数
            
            
              typescript
              
              
            
          
          // 抛出错误的函数
function throwError(message: string): never {
  throw new Error(message);
}
// 无限循环的函数
function infiniteLoop(): never {
  while (true) {
    console.log('Looping forever...');
  }
}
        2. never 的类型检测
            
            
              typescript
              
              
            
          
          type IsNever<T> = [T] extends [never] ? true : false;
type Test1 = IsNever<never>;        // true
type Test2 = IsNever<string>;       // false
type Test3 = IsNever<number | never>; // false
        never 在类型系统中的行为
1. 在联合类型中
never 在联合类型中会被自动忽略:
            
            
              typescript
              
              
            
          
          type Union1 = string | never;           // string
type Union2 = number | never | boolean; // number | boolean
type Union3 = never | never;            // never
        2. 在交叉类型中
不可能的类型组合会产生 never:
            
            
              typescript
              
              
            
          
          type Intersection1 = string & number;   // never
type Intersection2 = { a: number } & { a: string }; // never
        3. 数组中的 never
            
            
              typescript
              
              
            
          
          type EmptyArray = never[];  // 空数组类型
const arr: EmptyArray = []; // 只能是空数组
        实际应用场景
1. 详尽性检查(Exhaustiveness Checking)
这是 never 类型最重要的应用之一:
            
            
              typescript
              
              
            
          
          type Shape =
  | { kind: 'circle'; radius: number }
  | { kind: 'square'; sideLength: number }
  | { kind: 'triangle'; base: number; height: number };
function getArea(shape: Shape): number {
  switch (shape.kind) {
    case 'circle':
      return Math.PI * shape.radius ** 2;
    case 'square':
      return shape.sideLength ** 2;
    case 'triangle':
      return (shape.base * shape.height) / 2;
    default:
      // 如果 Shape 类型添加了新成员但这里没处理,TypeScript 会报错
      const _exhaustiveCheck: never = shape;
      return _exhaustiveCheck;
  }
}
        2. 类型过滤
使用条件类型从联合类型中过滤掉某些类型:
            
            
              typescript
              
              
            
          
          // 过滤掉 null 和 undefined
type NonNullable<T> = T extends null | undefined ? never : T;
type Result = NonNullable<string | number | null | undefined>; // string | number
// 提取字符串类型
type ExtractString<T> = T extends string ? T : never;
type OnlyStrings = ExtractString<string | number | boolean>; // string
// 排除特定类型
type Diff<T, U> = T extends U ? never : T;
type Filtered = Diff<'a' | 'b' | 'c', 'b'>; // 'a' | 'c'
        3. 属性排除
从对象类型中排除特定属性:
            
            
              typescript
              
              
            
          
          type RemoveKindField<T> = {
  [K in keyof T as K extends 'kind' ? never : K]: T[K];
};
type Circle = { kind: 'circle'; radius: number };
type WithoutKind = RemoveKindField<Circle>; // { radius: number }
        4. 类型保护
            
            
              typescript
              
              
            
          
          function assertNever(x: never): never {
  throw new Error(`Unexpected object: ${x}`);
}
function processValue(value: string | number) {
  if (typeof value === 'string') {
    console.log(value.toUpperCase());
  } else if (typeof value === 'number') {
    console.log(value.toFixed(2));
  } else {
    // 这里的 value 类型应该是 never
    assertNever(value);
  }
}
        never 与 void 的区别
理解 never 和 void 的区别非常重要:
| 特性 | void | 
never | 
|---|---|---|
| 返回值 | 函数正常结束,返回 undefined | 
函数永远不会正常结束 | 
| 使用场景 | 函数没有返回值 | 抛出错误、无限循环 | 
| 类型兼容性 | 可以赋值给 void | 
不能赋值给其他类型 | 
| 联合类型 | 保留在联合类型中 | 从联合类型中移除 | 
            
            
              typescript
              
              
            
          
          function returnsVoid(): void {
  console.log('返回 void');
  // 隐式返回 undefined
}
function returnsNever(): never {
  throw new Error('永远不会返回');
  // 函数永远不会正常结束
}
// void 可以赋值给 void
let v: void = returnsVoid();
// never 不能赋值给其他类型
// let n: string = returnsNever(); // 错误!
        高级用法
1. 递归类型中的 never
            
            
              typescript
              
              
            
          
          // 深度只读类型
type DeepReadonly<T> = {
  readonly [P in keyof T]: T[P] extends object
    ? T[P] extends Function
      ? T[P]
      : DeepReadonly<T[P]>
    : T[P];
};
        2. 函数参数中的 never
            
            
              typescript
              
              
            
          
          type FunctionWithNever = (arg: never) => void;
// 这个函数无法被调用,因为没有值可以赋给 never 类型
        3. 条件类型中的分布式特性
            
            
              typescript
              
              
            
          
          // 当 T 是联合类型时,条件类型会分布到每个成员上
type ToArray<T> = T extends any ? T[] : never;
type StringArray = ToArray<string | number>; // string[] | number[]
        常见误区
1. 不要混淆 never 和 void
            
            
              typescript
              
              
            
          
          // 错误:这个函数实际上会返回 undefined
function wrongNever(): never {
  console.log('This is wrong');
  // 这里应该抛出错误或无限循环
}
// 正确:使用 void
function correctVoid(): void {
  console.log('This is correct');
}
        2. 注意 never 在条件类型中的行为
            
            
              typescript
              
              
            
          
          // 注意:never 在条件类型中可能会产生意外的结果
type Test<T> = T extends never ? true : false;
type Result1 = Test<never>; // never (!)
type Result2 = Test<string>; // false
// 正确的写法:使用元组包装
type CorrectTest<T> = [T] extends [never] ? true : false;
type CorrectResult1 = CorrectTest<never>; // true
type CorrectResult2 = CorrectTest<string>; // false
        最佳实践
- 使用 never 进行详尽性检查:在 switch 语句的 default 分支中使用 never 确保所有情况都被处理
 - 类型过滤时使用 never:在条件类型中使用 never 来过滤掉不需要的类型
 - 避免误用:不要在不应该使用 never 的地方使用它
 - 理解类型系统:深入理解 never 在类型系统中的行为
 
总结
never 类型是 TypeScript 类型系统中一个强大但容易被误解的特性。正确理解和使用 never 可以帮助你:
- 编写更安全的代码
 - 进行编译时的详尽性检查
 - 创建更精确的类型定义
 - 避免运行时错误
 
通过掌握 never 类型,你可以更好地利用 TypeScript 的类型系统来编写健壮、可维护的代码。