any,unknown,never

92 阅读2分钟

unknown

用于表示不确定类型的值

1.赋值

  • 只能赋值给any和unknown以外类型的变量,避免了any的变量污染问题
let v: unknown = 123;
let v1: boolean = v; // 报错
let v2: number = v; // 报错
  • 所有类型的值都可以赋值给unknown类型的变量
let x: unknown;
x = true; // 正确ts
x = 42; // 正确
x = "Hello World"; // 正确

直接调用unknown类型变量的方法和属性。 会报错

let v1: unknown = { foo: 123 };
v1.foo; // 报错

let v2: unknown = "hello";
v2.trim(); // 报错

let v3: unknown = (n = 0) => n + 1;
v3(); // 报错

unknown也可以视为所有其他类型(除了any)的全集

2. 常见应用场景

2.1函数参数或返回值类型

当函数接收或返回不确定类型的值时,使用unknown替代any可以保持类型安全。

function fetchData(): unknown {
  // 模拟返回未知类型的数据
  return JSON.parse('{"name": "Alice"}');
}

const data = fetchData();
// 使用前必须检查类型
if (typeof data === 'object' && data !== null) {
  console.log((data as { name: string }).name); // 类型断言
}

2.2类型守卫与类型收窄

unknown常用于类型守卫中,确保在使用值之前先验证其类型。

function isString(value: unknown): value is string {
  return typeof value === 'string';
}

function process(value: unknown) {
  if (isString(value)) {
    value.toUpperCase(); // 安全:TypeScript知道value是string
  }
}

2.3泛型约束

在泛型中,使用unknown作为约束条件,确保类型参数是 "任意类型" 但仍需通过类型检查。

function logValue<T extends unknown>(value: T) {
  // 无法直接访问value的属性,需先检查类型
  console.log(value);
}

never

代表的是那些永远不会出现的值的类型。

1.赋值

  • never 可以赋值给任何类型。
let n: never = (() => { throw new Error(); })();
let num: number = n; // 可以赋值给任何类型。
  • 只有 never 类型的值才能赋值给 never 类型的变量。
let a: never = never; // 正确
let b: never = 123;   // 错误,number 类型不能赋值给 never 类型

2. 主要应用场景

2.1 函数不会返回值

当函数总是抛出异常或者陷入无限循环时,其返回类型可标注为 never

// 抛出异常的函数
function throwError(message: string): never {
  throw new Error(message);
}

// 无限循环的函数
function infiniteLoop(): never {
  while (true) {}
}

2.2 永不为真的类型守卫

在类型收窄的过程中,如果某个变量的类型被收窄到不可能的情况,就会出现 never 类型。

function printValue(value: string | number) {
  if (typeof value === 'string') {
    console.log(value.toUpperCase()); // value 是 string 类型
  } else if (typeof value === 'number') {
    console.log(value.toFixed(2));    // value 是 number 类型
  } else {
    // 此时 value 的类型是 never,因为没有其他可能了
    const check: never = value; // 用于类型检查
  }
}

2.3 类型系统中的类型检查

never 能够在联合类型、交叉类型或者条件类型中发挥作用,帮助进行类型检查。

// 从联合类型中排除某些类型
type ExcludeString<T> = T extends string ? never : T;
type OnlyNumbers = ExcludeString<string | number | boolean>; // number | boolean