any、unknown、never 和 void 之间有什么区别?
在 TypeScript 中,any、unknown、never 和 void 都是特殊的类型,它们在类型系统中的地位和用途各不相同。
为了让你更直观地理解,我们可以把它们分为两组来对比:
- 包含一切的类型(Top Types):
anyvsunknown - 表示“无”或“不可能”的类型:
voidvsnever
以下是详细的区别解析:
1. any vs unknown (顶级类型)
这两个类型都可以接收任何值,但在使用这些值时,规则完全不同。
any (任意类型)
- 定义: “我不在乎类型,请关闭类型检查。”
- 特点: 它是类型系统的“逃生舱”。你可以把任何值赋给
any,也可以在any类型的变量上进行任何操作(调用方法、访问属性),TypeScript 编译器不会报错。 - 代价: 失去了 TypeScript 的类型保护,可能导致运行时错误。
typescript
let value: any = "hello";
value = 123; // OK
value = true; // OK
value.foo(); // OK (编译通过,但运行时会报错,因为 boolean 没有 foo 方法)
value(); // OK (编译通过,运行时报错)
const b: boolean = value; // OK (any 可以赋值给任何类型)
unknown (未知类型)
- 定义: “我不知道这是什么类型,但在我确认之前,不允许你乱用。”
- 特点: 它是
any的类型安全版本。你可以把任何值赋给unknown,但是,你不能直接调用它的方法或访问属性,也不能把它赋值给其他具体类型的变量,除非你先进行类型收窄 (Type Narrowing)。
typescript
let value: unknown = "hello";
value = 123; // OK
value = true; // OK
// value.foo(); // Error: 对象类型为 'unknown'
// value(); // Error
// const b: boolean = value; // Error: 不能把 'unknown' 分配给 'boolean'
// 正确用法:必须先检查类型
if (typeof value === 'string') {
console.log(value.toUpperCase()); // OK,TS 知道这里它是 string
}
总结区别:
any是不安全的,允许做任何事。unknown是安全的,在判断具体类型之前,禁止做任何事。
2. void vs never (返回类型)
这两个类型通常用于函数的返回值,表示函数“不返回正常值”的情况,但程度不同。
void (空)
- 定义: “函数正常执行完了,但没有返回任何有意义的值。”
- 特点: 在 JavaScript 中,如果函数没有
return,它默认返回undefined。void类型正是表示这种情况。 - 赋值: 变量如果是
void类型,只能被赋值为undefined(如果strictNullChecks关闭,也可以是null)。
typescript
function logMessage(msg: string): void {
console.log(msg);
// 函数执行完毕,隐含 return undefined
}
const result = logMessage("Hi"); // result 的类型是 void (实际值是 undefined)
never (永不)
- 定义: “函数永远不会正常结束(无法到达终点)。”
- 特点: 表示代码流程根本不可能执行到这里。它是所有类型的子类型(底层类型,Bottom Type)。
- 场景:
- 抛出错误(异常中断)。
- 死循环(永远在运行)。
- 类型收窄时的“不可能情况”(Exhaustive Check)。
typescript
// 场景 1: 抛出错误
function throwError(msg: string): never {
throw new Error(msg);
// 代码永远不会执行到这里
}
// 场景 2: 死循环
function infiniteLoop(): never {
while (true) {
}
}
// 场景 3: 兜底检查 (Exhaustive Check)
type Direction = 'Up' | 'Down';
function check(dir: Direction) {
if (dir === 'Up') {
// ...
} else if (dir === 'Down') {
// ...
} else {
// 如果 dir 类型正确,这里永远不可达
// const n: never = dir;
}
}
总结区别:
void:函数能执行完,返回undefined。never:函数不能正常执行完(报错或死循环),什么都不返回。
一张表总结
| 类型 | 含义 | 能赋值给它吗? | 它能赋值给别人吗? | 典型用途 |
|---|---|---|---|---|
any |
任意 | ✅ 是 (任何值) | ✅ 是 (任何类型) | 迁移旧代码、绕过类型检查 (尽量少用) |
unknown |
未知 | ✅ 是 (任何值) | ❌ 否 (仅能赋给 any 或 unknown) |
替代 any,处理不确定的输入 (如 API 数据) |
void |
空 | ⚠️ 仅 undefined |
❌ 否 | 函数没有返回值 |
never |
不可能 | ❌ 否 (除了 never 本身) |
✅ 是 (所有类型) | 抛错函数、死循环、类型守卫兜底 |
最佳实践建议
- 尽量避免使用
any:除非你在快速迁移 JS 代码,否则它会破坏 TS 的价值。 - 优先使用
unknown:当你不知道一个变量是什么类型时(例如JSON.parse的结果),用unknown强迫自己在使用前进行类型检查。 - 函数无返回值用
void:这是最常见的用法。 - 利用
never做全面性检查:在switch语句的default分支使用never,可以确保你处理了联合类型中的所有情况。