← 返回导航

类型守卫(is 关键字)

进阶技巧 · 基础

场景说明

类型守卫(Type Guard)是 TypeScript 中用于在运行时收窄类型的关键机制。arg is Type 语法允许你定义一个返回布尔值的函数,告诉 TS 编译器:如果函数返回 true,则参数就是指定的类型。这在处理联合类型、判断 API 返回值、过滤数组等场景中非常实用。

完整代码


      
// 类型守卫:arg is Type 的用法

// 1. 基础类型守卫:isString
function isString(value: unknown): value is string {
  return typeof value === 'string';
}

function print(value: string | number) {
  if (isString(value)) {
    console.log(value.toUpperCase());  // value 被收窄为 string
  } else {
    console.log(value.toFixed(2));      // value 被收窄为 number
  }
}

// 2. 对象类型守卫:isUser
interface User {
  id: number;
  name: string;
  email: string;
}

interface Admin {
  id: number;
  name: string;
  role: 'admin' | 'superadmin';
  permissions: string[];
}

function isUser(obj: unknown): obj is User {
  return (
    typeof obj === 'object' &&
    obj !== null &&
    'email' in obj &&
    'id' in obj
  );
}

type Person = User | Admin;

function handlePerson(person: Person) {
  if (isUser(person)) {
    console.log(person.email);  // User 类型,可以访问 email
  } else {
    console.log(person.permissions);  // Admin 类型
  }
}

// 3. 过滤数组中的 null/undefined
function isNonNullable<T>(value: T): value is NonNullable<typeof value> {
  return value !== null && value !== undefined;
}

const arr = [1, null, 2, undefined, 3];
const filtered = arr.filter(isNonNullable);  // number[]

// 4. 判断 API 响应是否有效
interface SuccessResponse {
  success: true;
  data: unknown;
}

interface ErrorResponse {
  success: false;
  message: string;
  code: number;
}

type ApiResponse = SuccessResponse | ErrorResponse;

function isSuccessResponse(res: ApiResponse): res is SuccessResponse {
  return res.success === true;
}

关键点解析

使用示例与类型推导


      
// 实战:处理多种事件类型

interface ClickEvent { type: 'click'; x: number; y: number; }
interface KeyEvent { type: 'keydown'; key: string; }
interface ScrollEvent { type: 'scroll'; scrollTop: number; }

type AppEvent = ClickEvent | KeyEvent | ScrollEvent;

function isClickEvent(e: AppEvent): e is ClickEvent {
  return e.type === 'click';
}

function handleEvent(event: AppEvent) {
  if (isClickEvent(event)) {
    console.log(`点击位置: ${event.x}, ${event.y}`);  // ClickEvent
  } else if (event.type === 'keydown') {
    console.log(`按键: ${event.key}`);  // KeyEvent(discriminated union)
  } else {
    console.log(`滚动位置: ${event.scrollTop}`);  // ScrollEvent
  }
}
在 Playground 中尝试