null和undefined是 TypeScript 中的两个基本类型,分别表示"空值"和"未定义"。
let u: undefined = undefined
let n: null = null
console.log(u) // undefined
console.log(n) // null
默认情况下,null 和 undefined 是所有类型的子类型:
let num: number = undefined // 正确(非严格模式)
let str: string = null // 正确(非严格模式)
开启 strictNullChecks 后,null 和 undefined 只能赋值给自身或 any:
let num: number = undefined // 错误
let str: string = null // 错误
let u: undefined = undefined // 正确
let n: null = null // 正确
使用联合类型处理可能为空的值:
let name: string | null = null
let age: number | undefined = undefined
name = "张三" // 正确
age = 25 // 正确
可选属性自动包含 undefined:
interface User {
name: string
age?: number
}
const user1: User = { name: "张三" }
const user2: User = { name: "李四", age: 25 }
const user3: User = { name: "王五", age: undefined }
可选参数自动包含 undefined:
function greet(name: string, greeting?: string): string {
return greeting ? `${greeting},${name}` : `你好,${name}`
}
greet("张三") // "你好,张三"
greet("张三", "早上好") // "早上好,张三"
greet("张三", undefined) // "你好,张三"
function printLength(str: string | null): void {
if (str === null) {
console.log("字符串为空")
return
}
console.log(str.length)
}
function printValue(value: string | undefined): void {
if (value === undefined) {
console.log("值未定义")
return
}
console.log(value)
}
function process(value: string | null | undefined): void {
if (value == null) { // 检查 null 和 undefined
console.log("值为空")
return
}
console.log(value)
}
使用 ! 断言值不为 null 或 undefined:
let name: string | null = "张三"
console.log(name!.toUpperCase()) // "张三"
let element = document.getElementById("app")
element!.innerHTML = "hello"
使用 ?. 安全访问属性:
interface User {
name: string
address?: {
city: string
}
}
const user: User = { name: "张三" }
console.log(user.address?.city) // undefined
console.log(user.address?.city?.length) // undefined
使用 ?? 提供默认值:
let name: string | null = null
let age: number | undefined = undefined
console.log(name ?? "匿名") // "匿名"
console.log(age ?? 0) // 0
// 与 || 的区别
let count = 0
console.log(count || 10) // 10(0 是 falsy)
console.log(count ?? 10) // 0(0 不是 null/undefined)
interface ApiResponse<T> {
data: T | null
error: string | null
}
function handleResponse<T>(response: ApiResponse<T>): T {
if (response.error !== null) {
throw new Error(response.error)
}
if (response.data === null) {
throw new Error("数据为空")
}
return response.data
}
interface User {
id: number
name: string
email: string | null
}
async function findUser(id: number): Promise<User | null> {
const user = await db.query("SELECT * FROM users WHERE id = ?", [id])
return user ?? null
}
async function getUserEmail(id: number): Promise<string> {
const user = await findUser(id)
if (user === null) {
throw new Error("用户不存在")
}
return user.email ?? "未设置邮箱"
}
interface Config {
host: string
port?: number
timeout?: number
}
function createServer(config: Config): void {
const port = config.port ?? 3000
const timeout = config.timeout ?? 5000
console.log(`服务器启动: ${config.host}:${port}`)
console.log(`超时时间: ${timeout}ms`)
}
let a: null = null
let b: undefined = undefined
console.log(a === b) // false
console.log(a == b) // true
console.log(typeof null) // "object"(历史遗留问题)
console.log(typeof undefined) // "undefined"
开启严格模式可以避免很多空值问题:
{
"compilerOptions": {
"strictNullChecks": true
}
}