类型守卫(Type Guards)
概述
类型守卫是一种运行时检查,用于缩小变量的类型范围,使 TypeScript 能够更精确地推断类型。
typeof 类型守卫
基本用法
// typeof 类型守卫
function processValue(value: string | number): string {
if (typeof value === 'string') {
// 此处 TypeScript 知道 value 是 string 类型
return value.toUpperCase();
}
// 此处 TypeScript 知道 value 是 number 类型
return value.toFixed(2);
}
// 检查多种类型
function handle(value: string | number | boolean): void {
if (typeof value === 'string') {
console.log(value.length);
} else if (typeof value === 'number') {
console.log(value.toFixed(2));
} else {
console.log(value ? 'true' : 'false');
}
}
instanceof 类型守卫
基本用法
// instanceof 类型守卫
class Dog {
bark(): void {
console.log('Woof!');
}
}
class Cat {
meow(): void {
console.log('Meow!');
}
}
function makeSound(animal: Dog | Cat): void {
if (animal instanceof Dog) {
animal.bark(); // TypeScript 知道 animal 是 Dog
} else {
animal.meow(); // TypeScript 知道 animal 是 Cat
}
}
检查内置类型
// 检查内置类型
function formatDate(value: string | Date): string {
if (value instanceof Date) {
return value.toISOString();
}
return new Date(value).toISOString();
}
// 检查错误类型
function handleError(error: Error | string): void {
if (error instanceof Error) {
console.error(error.message);
console.error(error.stack);
} else {
console.error(error);
}
}
in 类型守卫
基本用法
// in 类型守卫
interface Fish {
swim: () => void;
name: string;
}
interface Bird {
fly: () => void;
name: string;
}
function move(animal: Fish | Bird): void {
if ('swim' in animal) {
animal.swim(); // TypeScript 知道 animal 是 Fish
} else {
animal.fly(); // TypeScript 知道 animal 是 Bird
}
}
检查可选属性
// 检查可选属性
interface User {
id: number;
name: string;
email?: string;
phone?: string;
}
function getContact(user: User): string {
if ('email' in user && user.email) {
return user.email;
}
if ('phone' in user && user.phone) {
return user.phone;
}
return 'No contact info';
}
自定义类型守卫
基本语法
// 自定义类型守卫函数
function isString(value: any): value is string {
return typeof value === 'string';
}
function isNumber(value: any): value is number {
return typeof value === 'number';
}
// 使用
function process(value: string | number): void {
if (isString(value)) {
console.log(value.toUpperCase());
} else {
console.log(value.toFixed(2));
}
}
检查对象类型
// 检查对象类型
interface User {
id: number;
name: string;
email: string;
}
interface Admin {
id: number;
name: string;
permissions: string[];
}
function isUser(obj: any): obj is User {
return (
typeof obj === 'object' &&
typeof obj.id === 'number' &&
typeof obj.name === 'string' &&
typeof obj.email === 'string'
);
}
function isAdmin(obj: any): obj is Admin {
return (
typeof obj === 'object' &&
typeof obj.id === 'number' &&
typeof obj.name === 'string' &&
Array.isArray(obj.permissions)
);
}
检查联合类型
// 检查联合类型
type StringOrNumber = string | number;
function isString(value: StringOrNumber): value is string {
return typeof value === 'string';
}
function process(value: StringOrNumber): string {
if (isString(value)) {
return value.toUpperCase();
}
return value.toFixed(2);
}
实际应用示例
1. API 响应处理
interface SuccessResponse<T> {
success: true;
data: T;
}
interface ErrorResponse {
success: false;
error: string;
}
type ApiResponse<T> = SuccessResponse<T> | ErrorResponse;
function isSuccess<T>(response: ApiResponse<T>): response is SuccessResponse<T> {
return response.success;
}
function handleResponse<T>(response: ApiResponse<T>): T | null {
if (isSuccess(response)) {
return response.data;
}
console.error(response.error);
return null;
}
2. 表单验证
interface ValidField {
isValid: true;
value: string;
}
interface InvalidField {
isValid: false;
error: string;
}
type FieldValidation = ValidField | InvalidField;
function isValidField(field: FieldValidation): field is ValidField {
return field.isValid;
}
function processForm(fields: FieldValidation[]): string[] {
return fields
.filter(isValidField)
.map(field => field.value);
}
3. 状态管理
interface LoadingState {
status: 'loading';
}
interface SuccessState<T> {
status: 'success';
data: T;
}
interface ErrorState {
status: 'error';
error: string;
}
type AsyncState<T> = LoadingState | SuccessState<T> | ErrorState;
function isSuccess<T>(state: AsyncState<T>): state is SuccessState<T> {
return state.status === 'success';
}
function isError<T>(state: AsyncState<T>): state is ErrorState {
return state.status === 'error';
}
function handleState<T>(state: AsyncState<T>): T | null {
if (isSuccess(state)) {
return state.data;
}
if (isError(state)) {
console.error(state.error);
}
return null;
}
4. DOM 元素检查
function isInputElement(element: HTMLElement): element is HTMLInputElement {
return element instanceof HTMLInputElement;
}
function isButtonElement(element: HTMLElement): element is HTMLButtonElement {
return element instanceof HTMLButtonElement;
}
function handleElement(element: HTMLElement): void {
if (isInputElement(element)) {
console.log('Input value:', element.value);
} else if (isButtonElement(element)) {
console.log('Button text:', element.textContent);
}
}
类型守卫的组合
组合多个守卫
// 组合多个类型守卫
interface Dog {
bark: () => void;
}
interface Cat {
meow: () => void;
}
interface Bird {
fly: () => void;
}
type Animal = Dog | Cat | Bird;
function isDog(animal: Animal): animal is Dog {
return 'bark' in animal;
}
function isCat(animal: Animal): animal is Cat {
return 'meow' in animal;
}
function isBird(animal: Animal): animal is Bird {
return 'fly' in animal;
}
function handleAnimal(animal: Animal): void {
if (isDog(animal)) {
animal.bark();
} else if (isCat(animal)) {
animal.meow();
} else if (isBird(animal)) {
animal.fly();
}
}
最佳实践
- 优先使用 typeof 和 instanceof
- 自定义类型守卫用于复杂检查
- 守卫函数返回类型使用
value is Type - 避免在守卫函数中修改值
// 好的做法
function isUser(obj: any): obj is User {
return (
typeof obj === 'object' &&
typeof obj.id === 'number' &&
typeof obj.name === 'string'
);
}
// 避免
function isUser(obj: any): boolean {
return (
typeof obj === 'object' &&
typeof obj.id === 'number' &&
typeof obj.name === 'string'
);
}
参考
目录