Typescript
类型守卫函数
类型守卫函数(Type Predicate Function)通过返回值 param is Type 告诉 TypeScript:如果函数返回 true,则 param 在该分支内是指定类型。
function isString(value: unknown): value is string {
return typeof value === 'string'
}调用后,TypeScript 在 if 分支内自动收窄类型:
function print(value: string | number) {
if (isString(value)) {
console.log(value.toUpperCase()) // value: string
} else {
console.log(value.toFixed(2)) // value: number
}
}与类型断言的区别
as 断言是强制告诉编译器"我知道它是什么类型",运行时不做任何检查,断言错误只会在运行时报错。
// 断言:跳过检查,不安全
const len = (value as string).length // 如果 value 不是 string,运行时出错
// 类型守卫:先验证,再使用,安全
if (isString(value)) {
const len = value.length // TypeScript 确认 value 是 string
}常用模式
检查原始类型
function isNumber(value: unknown): value is number {
return typeof value === 'number' && !Number.isNaN(value)
}
function isString(value: unknown): value is string {
return typeof value === 'string'
}检查类实例
function isDate(value: unknown): value is Date {
return value instanceof Date
}检查联合类型中的具体成员
通过判断某个特有属性是否存在来区分联合类型的成员:
interface Circle {
kind: 'circle'
radius: number
}
interface Rectangle {
kind: 'rect'
width: number
height: number
}
type Shape = Circle | Rectangle
function isCircle(shape: Shape): shape is Circle {
return shape.kind === 'circle'
}
function getArea(shape: Shape) {
if (isCircle(shape)) {
return Math.PI * shape.radius ** 2 // shape: Circle
}
return shape.width * shape.height // shape: Rectangle
}过滤数组
类型守卫函数可以直接传给 Array.filter,过滤后的数组类型自动收窄:
const values: (string | null | undefined)[] = ['a', null, 'b', undefined, 'c']
function isString(v: string | null | undefined): v is string {
return typeof v === 'string'
}
const strings = values.filter(isString)
// strings: string[],而非 (string | null | undefined)[]不使用类型守卫时,filter 无法收窄类型:
// ❌ 类型仍为 (string | null | undefined)[]
const strings = values.filter(v => v !== null && v !== undefined)验证外部数据结构
处理 API 响应或 JSON 数据时,用类型守卫替代断言:
interface User {
id: number
name: string
}
function isUser(data: unknown): data is User {
return (
typeof data === 'object' &&
data !== null &&
typeof (data as User).id === 'number' &&
typeof (data as User).name === 'string'
)
}
async function fetchUser(id: number) {
const res = await fetch(`/api/users/${id}`)
const data: unknown = await res.json()
if (isUser(data)) {
console.log(data.name) // data: User
} else {
throw new Error('Invalid user data')
}
}