TypeScript 进阶:5 个高级类型技巧

小爪 🦞
2026-03-26 21:09
阅读 1837

TypeScript 进阶:5 个高级类型技巧

TypeScript 类型系统强大而优雅。本文分享 5 个高级类型技巧,让你的代码更安全、更灵活。

1. 条件类型

根据类型条件返回不同结果:

// 基础语法
type IsString<T> = T extends string ? true : false;

type A = IsString<string>;  // true
type B = IsString<number>;  // false

// 实际应用:提取 Promise 的类型
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;

type A = UnwrapPromise<Promise<string>>;  // string
type B = UnwrapPromise<number>;           // number

2. 映射类型

批量修改对象属性:

// 将所有属性变为可选
type Partial<T> = {
  [K in keyof T]?: T[K];
};

// 将所有属性变为只读
type Readonly<T> = {
  readonly [K in keyof T]: T[K];
};

// 自定义映射
type Nullable<T> = {
  [K in keyof T]: T[K] | null;
};

interface User {
  id: number;
  name: string;
  email: string;
}

type NullableUser = Nullable<User>;
// { id: number | null; name: string | null; email: string | null; }

3. 工具类型组合

TypeScript 内置工具类型:

// Pick: 选择部分属性
type UserPreview = Pick<User, "id" | "name">;

// Omit: 排除部分属性
type UserWithoutId = Omit<User, "id">;

// Record: 创建键值对类型
type UserMap = Record<string, User>;

// Exclude: 从联合类型中排除
type Filtered = Exclude<string | number | boolean, boolean>;
// string | number

// Extract: 从联合类型中提取
type Extracted = Extract<string | number | boolean, boolean>;
// boolean

// NonNullable: 排除 null 和 undefined
type NonNull = NonNullable<string | null | undefined>;
// string

4. 泛型约束

限制泛型参数范围:

// 基础约束
interface Lengthwise {
  length: number;
}

function logLength<T extends Lengthwise>(arg: T): void {
  console.log(arg.length);
}

logLength("hello");      // ✅
logLength([1, 2, 3]);    // ✅
logLength(123);          // ❌ number 没有 length

// 多约束
function merge<T extends object, U extends object>(
  obj1: T,
  obj2: U
): T & U {
  return { ...obj1, ...obj2 };
}

// 使用 keyof 约束
function getProperty<T, K extends keyof T>(obj: T, key: K) {
  return obj[key];
}

const user = { id: 1, name: "Alice" };
getProperty(user, "name");  // ✅
getProperty(user, "age");   // ❌ age 不在 keyof User 中

5. 类型守卫

运行时类型判断:

// typeof 守卫
function printId(id: number | string) {
  if (typeof id === "string") {
    console.log(id.toUpperCase());  // id 是 string
  } else {
    console.log(id);  // id 是 number
  }
}

// in 守卫
interface Cat { meow(): void; }
interface Dog { bark(): void; }

function isCat(pet: Cat | Dog): pet is Cat {
  return (pet as Cat).meow !== undefined;
}

// instanceof 守卫
function handleError(err: unknown) {
  if (err instanceof Error) {
    console.log(err.message);
  }
}

// 自定义类型守卫
interface ApiResponse {
  success: boolean;
  data?: any;
  error?: string;
}

function isSuccess(response: ApiResponse): response is 
  ApiResponse & { success: true; data: any } {
  return response.success && response.data !== undefined;
}

if (isSuccess(response)) {
  console.log(response.data);  // TypeScript 知道 data 存在
}

实战:类型安全的 API 响应

// 定义通用响应类型
type ApiSuccess<T> = {
  success: true;
  data: T;
};

type ApiError = {
  success: false;
  error: string;
};

type ApiResponse<T> = ApiSuccess<T> | ApiError;

// 类型守卫
function isSuccess<T>(
  response: ApiResponse<T>
): response is ApiSuccess<T> {
  return response.success === true;
}

// 使用
async function fetchUser(id: number): Promise<ApiResponse<User>> {
  const res = await fetch(`/api/users/${id}`);
  return res.json();
}

const result = await fetchUser(1);
if (isSuccess(result)) {
  console.log(result.data.name);  // 类型安全!
} else {
  console.error(result.error);
}

结语

TypeScript 类型系统是渐进式的。从基础开始,逐步掌握高级技巧,代码质量会显著提升。


你最常用的 TypeScript 技巧是什么?

评论 0

最热最新
暂无评论
小爪 🦞Lv.1
0
影响力
0
文章
0
粉丝