类型守卫是在运行时检查类型的表达式,帮助 TypeScript 在特定代码块中确定变量的具体类型。类型守卫让我们可以安全地访问联合类型中特定类型的属性和方法。
typeof 操作符用于检查原始类型。
function format(value: string | number): string {
if (typeof value === "string") {
return value.toUpperCase()
}
return value.toFixed(2)
}
console.log(format("hello"))
console.log(format(3.14159))
typeof 可以识别 string、number、boolean、symbol、undefined、function 和 object 类型。
instanceof 操作符用于检查类实例。
class Dog {
bark(): void {
console.log("汪汪叫")
}
}
class Cat {
meow(): void {
console.log("喵喵叫")
}
}
function makeSound(animal: Dog | Cat): void {
if (animal instanceof Dog) {
animal.bark()
} else {
animal.meow()
}
}
const dog = new Dog()
const cat = new Cat()
makeSound(dog)
makeSound(cat)
instanceof 检查对象是否是某个类的实例,适用于类类型。
in 操作符检查对象是否有某个属性。
interface Bird {
fly(): void
layEggs(): void
}
interface Fish {
swim(): void
layEggs(): void
}
function move(animal: Bird | Fish): void {
if ("fly" in animal) {
animal.fly()
} else {
animal.swim()
}
animal.layEggs()
}
in 操作符检查属性是否存在,适用于区分有不同属性的对象类型。
可以创建自定义的类型守卫函数。
interface Fish {
swim: () => void
}
interface Bird {
fly: () => void
}
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined
}
function move(pet: Fish | Bird): void {
if (isFish(pet)) {
pet.swim()
} else {
pet.fly()
}
}
pet is Fish 是类型谓词,告诉 TypeScript 如果函数返回 true,则 pet 是 Fish 类型。
类型谓词语法:parameterName is Type。
interface Admin {
name: string
permissions: string[]
}
interface User {
name: string
email: string
}
function isAdmin(user: Admin | User): user is Admin {
return (user as Admin).permissions !== undefined
}
function processUser(user: Admin | User): void {
if (isAdmin(user)) {
console.log(`管理员权限: ${user.permissions.join(", ")}`)
} else {
console.log(`用户邮箱: ${user.email}`)
}
}
类型谓词让类型守卫更加语义化和可复用。
类型守卫常用于检查 null 和 undefined。
function process(value: string | null): string {
if (value === null) {
return "空值"
}
return value.toUpperCase()
}
console.log(process("hello"))
console.log(process(null))
直接比较 === null 或 === undefined 可以缩小类型范围。
可选链和空值合并运算符也可以用于处理 null 和 undefined。
interface User {
name: string
address?: {
city: string
}
}
function getCity(user: User): string {
return user.address?.city ?? "未知城市"
}
console.log(getCity({ name: "张三", address: { city: "北京" } }))
console.log(getCity({ name: "李四" }))
?. 安全访问可能为 null 或 undefined 的属性,?? 提供默认值。
类型断言可以强制指定类型,但不进行运行时检查。
interface User {
name: string
age: number
}
function process(value: unknown): void {
const user = value as User
console.log(user.name)
}
process({ name: "张三", age: 25 })
类型断言不安全,应该优先使用类型守卫。
类型守卫在实际开发中常用于处理 API 响应。
interface SuccessResponse {
status: "success"
data: {
id: number
name: string
}
}
interface ErrorResponse {
status: "error"
error: string
}
type ApiResponse = SuccessResponse | ErrorResponse
function isSuccess(response: ApiResponse): response is SuccessResponse {
return response.status === "success"
}
function handleResponse(response: ApiResponse): void {
if (isSuccess(response)) {
console.log(`成功: ${response.data.name}`)
} else {
console.log(`错误: ${response.error}`)
}
}
handleResponse({
status: "success",
data: { id: 1, name: "张三" }
})
handleResponse({
status: "error",
error: "网络错误"
})
自定义类型守卫让代码更加清晰和可维护。
类型守卫是在运行时检查类型的表达式,帮助 TypeScript 确定变量的具体类型。typeof 用于原始类型,instanceof 用于类实例,in 操作符用于检查属性。自定义类型守卫使用类型谓词语法,可以创建可复用的类型检查函数。合理使用类型守卫可以让代码更加安全和可读。