🚀 如何使用TypeScript的null和undefined类型

📅 发布于 2026年1月 | 👤 作者:博主 | 🏷️ 标签:TypeScript, null, undefined, strictNullChecks, 类型安全, Web开发, 前端, 面试

欢迎来到我的博客文章!所有文章都是满满的前端干货,文章简明扼要。

基本概念

nullundefined 是 TypeScript 中的两个特殊类型,分别对应 JavaScript 中的两个原始值。

let u: undefined = undefined;
let n: null = null;

// 默认情况下,它们是所有类型的子类型
let num: number = undefined; // ✅ 默认情况下允许
let str: string = null; // ✅ 默认情况下允许

strictNullChecks 配置

TypeScript 的行为取决于 tsconfig.json 中的 strictNullChecks 配置。

❌ 关闭时(默认旧版本行为)

{
  "compilerOptions": {
    "strictNullChecks": false
  }
}
let name: string = null; // ✅ 允许
let age: number = undefined; // ✅ 允许

function greet(name: string) {
  console.log(name.toUpperCase()); // 可能运行时错误!
}

greet(null); // ✅ 编译通过,但运行时崩溃

✅ 开启时(推荐)

{
  "compilerOptions": {
    "strictNullChecks": true,
    "strict": true // 包含 strictNullChecks
  }
}
let name: string = null; // ❌ 错误
let age: number = undefined; // ❌ 错误

let nullableName: string | null = null; // ✅ 正确
let optionalAge: number | undefined = undefined; // ✅ 正确

null vs undefined 的区别

特性 null undefined
含义 明确表示"空值" 表示"未定义"或"缺失"
typeof "object"(历史遗留bug) "undefined"
使用场景 主动赋值为空 变量未初始化、函数无返回值
JSON.stringify 保留为 null 被忽略或转为 null
数值转换 转为 0 转为 NaN

非空断言操作符(Non-null Assertion)

1. ! 操作符

let name: string | null = "Alice";

// 告诉 TypeScript:我知道 name 不为 null
console.log(name!.length); // ✅ 编译通过

// 危险用法
let maybeNull: string | null = null;
console.log(maybeNull!.length); // ✅ 编译通过,❌ 运行时错误!

⚠️ 警告

非空断言会绕过 TypeScript 的类型检查,使用时要确保值确实不为 null/undefined,否则会导致运行时错误。

可选链操作符(Optional Chaining)

interface User {
  name: string;
  address?: {
    city: string;
    street?: string;
  };
}

const user: User = { name: "Alice" };

// ❌ 传统方式:冗长
const city1 = user && user.address && user.address.city;

// ✅ 可选链:简洁
const city2 = user?.address?.city; // undefined
const street = user?.address?.street; // undefined

空值合并操作符(Nullish Coalescing)

TypeScript 3.7+ 支持 ?? 操作符,用于处理 null 和 undefined。

// ?? 只在左侧为 null 或 undefined 时使用右侧值
const inputValue = null;
const defaultValue = "default";

const result1 = inputValue ?? defaultValue; // "default"
const result2 = inputValue || defaultValue; // "default"(相同结果)

?? vs || 的区别

// 区别:|| 会将 0、""、false 视为 falsy
const count = 0;
const countWithOr = count || 10; // 10(错误!)
const countWithNullish = count ?? 10; // 0(正确!)

const emptyString = "";
const strWithOr = emptyString || "default"; // "default"
const strWithNullish = emptyString ?? "default"; // ""(保留空字符串)

实战示例

示例 1:配置对象

interface Config {
  timeout?: number;
  retries?: number;
}

function createConnection(config: Config) {
  const timeout = config.timeout ?? 5000; // 默认 5000
  const retries = config.retries ?? 3; // 默认 3
  console.log(`Timeout: ${timeout$}, Retries: ${retries$}`);
}

createConnection({}); // Timeout: 5000, Retries: 3
createConnection({ timeout: 0 }); // Timeout: 0, Retries: 3

示例 2:API 响应处理

interface ApiResponse {
  data?: {
    user?: {
      name: string;
      email?: string;
    };
  };
}

function getUserEmail(response: ApiResponse): string {
  // ✅ 使用可选链 + 空值合并
  return response?.data?.user?.email ?? "No email provided";
}

const response1: ApiResponse = {};
console.log(getUserEmail(response1)); // "No email provided"

const response2: ApiResponse = {
  data: { user: { name: "Alice", email: "alice@example.com" } }
};
console.log(getUserEmail(response2)); // "alice@example.com"

示例 3:类型守卫

function processValue(value: string | null | undefined) {
  // 方法 1:显式检查
  if (value === null || value === undefined) {
    console.log("Value is null or undefined");
    return;
  }
  console.log(value.toUpperCase()); // value 类型收窄为 string

  // 方法 2:使用 ?? 提供默认值
  const safeValue = value ?? "default";
  console.log(safeValue.toUpperCase());
}

最佳实践

✅ 推荐做法

推荐模式

// ❌ 不推荐:冗长的检查
const city = user && user.address && user.address.city;

// ✅ 推荐:使用可选链 + 空值合并
const city = user?.address?.city ?? "Unknown";

// ❌ 不推荐:使用 || 可能导致意外行为
const count = config.count || 10; // 0 会被当作 falsy

// ✅ 推荐:使用 ?? 只处理 null/undefined
const count = config.count ?? 10; // 0 会被保留

常见陷阱

陷阱 1:typeof null === "object"

// ❌ 错误:typeof null 返回 "object"
if (typeof value === "object") {
  // value 可能是 null!
}

// ✅ 正确:显式检查 null
if (typeof value === "object" && value !== null) {
  // 现在 value 确实是对象
}

陷阱 2:JSON.stringify 的行为

const obj = {
  a: null,
  b: undefined,
  c: "value"
};

JSON.stringify(obj);
// 结果:{"a":null,"c":"value"}
// undefined 被忽略了!

核心要点总结

💡 关键知识点

← 返回首页