TypeScript 高级类型技巧

#typescript#types#generics
TypeScript 高级类型技巧

类型体操入门

TypeScript 的类型系统非常强大,掌握高级类型技巧能让你写出更安全的代码。

条件类型

根据条件推导类型:

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

type A = IsString<'hello'>; // true
type B = IsString<123>;     // false

// 分布式条件类型
type ToArray<T> = T extends any ? T[] : never;

type Result = ToArray<string | number>;
// 结果:string[] | number[]

映射类型

基于已有类型创建新类型:

// 只读类型
type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};

// 可选类型
type Partial<T> = {
  [P in keyof T]?: T[P];
};

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

type User = {
  name: string;
  age: number;
};

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

模板字面量类型

利用字符串模板创建类型:

// 基础用法
type Color = 'red' | 'green' | 'blue';
type Size = 'small' | 'medium' | 'large';

type Class = `${Color}-${Size}`;
// 'red-small' | 'red-medium' | 'red-large' | ...

// 实用场景:API 端点
type Method = 'GET' | 'POST' | 'PUT' | 'DELETE';
type Endpoint = `/api/users${'' | `/${string}`}`;

type FullEndpoint = `${Method} ${Endpoint}`;

递归类型

处理嵌套结构:

// 深度只读
type DeepReadonly<T> = {
  readonly [P in keyof T]: T[P] extends object
    ? DeepReadonly<T[P]>
    : T[P];
};

// 深度可选
type DeepPartial<T> = T extends object
  ? { [P in keyof T]?: DeepPartial<T[P]> }
  : T;

// 树形结构
type TreeNode = {
  name: string;
  children?: TreeNode[];
};

工具类型实战

提取 API 响应类型

interface ApiResponse<T> {
  code: number;
  message: string;
  data: T;
}

// 提取 data 类型
type ExtractData<T> = T extends ApiResponse<infer D> ? D : never;

type User = { id: number; name: string };
type UserData = ExtractData<ApiResponse<User>>;
// { id: number; name: string }

构建类型安全的表单

type FormFields<T> = {
  [K in keyof T]: {
    value: T[K];
    error?: string;
    touched: boolean;
  };
};

type LoginForm = {
  username: string;
  password: string;
};

type LoginFormState = FormFields<LoginForm>;

类型守卫

运行时类型检查:

// 用户自定义类型守卫
function isString(value: unknown): value is string {
  return typeof value === 'string';
}

// 类型保护
function processInput(input: string | number) {
  if (typeof input === 'string') {
    // 这里 input 被推断为 string
    return input.toUpperCase();
  }
  // 这里 input 被推断为 number
  return input.toFixed(2);
}

最佳实践

  1. 优先使用 interface:用于对象类型定义
  2. 谨慎使用 any:用 unknown 替代,强制类型检查
  3. 善用泛型:编写可复用的类型工具
  4. 类型即文档:好的类型名能说明意图

总结

高级类型技巧能提升代码质量和开发效率,但也要避免过度复杂化。记住:

类型系统是为了帮助开发者,而不是束缚开发者。