TypeScript中void、never、null、undefined的区别及适用场景
TypeScript中null、undefined、unknown、never四种类型的区别与实际示例
以下讨论完全聚焦TypeScript编译时类型,而非JavaScript运行时的值,核心讲TS类型系统里这四个特殊类型的语义差异和实际用法。
1. null类型
语义
专门标记主动赋值为空的对象值——意思是这个变量本应该指向一个对象,但我们明确让它暂时没有指向任何对象。
实际场景示例
// 声明一个明确为null的变量,比如未加载的用户头像 let userAvatar: null = null; // 从缓存取数据,找不到就返回null function getCachedUser(id: string): User | null { return userCache.has(id) ? userCache.get(id) : null; } const currentUser = getCachedUser("123"); // 必须先检查null,TS才会允许访问对象属性 if (currentUser !== null) { console.log(currentUser.nickname); // 编译时完全安全 }
2. undefined类型
语义
标记未初始化的变量或者函数中未传递的可选参数——强调"这个值还没被赋值",不是主动设为空。
实际场景示例
// 声明一个未初始化的变量,类型为undefined let tempConfig: undefined; // 函数的可选参数,没传的时候自动是undefined类型 function sendMessage(content: string, recipient?: string) { // recipient的类型是string | undefined const target = recipient || "全体成员"; console.log(`发送给${target}: ${content}`); } sendMessage("开会通知"); // 正常执行,recipient为undefined
3. unknown类型
语义
表示类型完全未知的值,是TypeScript里最安全的"任意类型"——和any最大的区别是,它不会绕过类型检查,你必须先明确它的类型才能操作。
实际场景示例
// 接口返回的数据类型不确定,用unknown接收 async function fetchApiData(url: string): Promise<unknown> { const response = await fetch(url); return response.json(); } async function renderUserInfo() { const rawData = await fetchApiData("/api/user"); // 直接访问rawData.name会报错:TS不知道它是什么类型 // console.log(rawData.name); // 必须先做类型收窄 if (typeof rawData === "object" && rawData !== null && "name" in rawData) { console.log(`用户名:${rawData.name}`); // 编译时安全 } }
4. never类型
语义
表示永远不会发生的情况——比如函数永远不会返回(要么抛错,要么无限循环),或者穷尽枚举所有可能性后的兜底分支。它是TS类型系统的"底部类型",没有任何值能赋值给它。
实际场景示例
// 抛错的函数,永远不会返回,类型为never function throwFatalError(msg: string): never { throw new Error(`致命错误:${msg}`); } // 无限循环的函数,永远不会返回 function keepRunning(): never { while (true) { console.log("程序持续运行中..."); } } // 穷尽检查枚举,确保没有遗漏分支 enum OrderStatus { Pending, Paid, Shipped, Cancelled } function handleOrder(status: OrderStatus) { switch (status) { case OrderStatus.Pending: console.log("订单待支付"); break; case OrderStatus.Paid: console.log("订单已支付"); break; case OrderStatus.Shipped: console.log("订单已发货"); break; case OrderStatus.Cancelled: console.log("订单已取消"); break; // 如果新增了枚举值,TS会直接编译报错,因为status无法赋值给never default: const _ensureAllCasesHandled: never = status; throwFatalError(`未知订单状态:${_ensureAllCasesHandled}`); } }
核心区别速览
| 类型 | 核心语义 | 编译时特点 |
|---|---|---|
| null | 主动设为空的对象值 | 需显式检查后才能访问对象属性 |
| undefined | 未赋值/未传递的值 | 常用于可选参数、未初始化变量 |
| unknown | 类型未知的值 | 必须类型收窄后操作,安全替代any |
| never | 永远不会发生的情况 | 无值可赋值,用于穷尽检查、永不返回的函数 |
内容的提问来源于stack exchange,提问作者Gerard
相关产品推荐
相关产品推荐

