1771220667
3m45s
100

TypeScript 高级类型技巧

TypeScript 类型系统的强大之处

TypeScript 的类型系统不仅能提供类型检查,还能实现强大的类型编程。本文深入探索 TypeScript 的高级类型特性。

1. 泛型约束

使用 extends 限制泛型类型:

// 基础泛型约束
          function getProperty<T, K extends keyof T>(obj: T, key: K) {
            return obj[key];
          }
          
          const user = { name: 'John', age: 30 };
          const name = getProperty(user, 'name'); // ✅
          const invalid = getProperty(user, 'email'); // ❌ Error
          
          // 多重约束
          interface Lengthwise {
            length: number;
          }
          
          function logLength<T extends Lengthwise>(arg: T): T {
            console.log(arg.length);
            return arg;
          }

2. 条件类型

根据条件选择类型:

// 基础条件类型
          type IsString<T> = T extends string ? true : false;
          
          type A = IsString<string>;  // true
          type B = IsString<number>;  // false
          
          // 实用条件类型
          type NonNullable<T> = T extends null | undefined ? never : T;
          
          type User = { name: string; age?: number };
          type RequiredUser = NonNullable<User>;
          
          // 分布式条件类型
          type ToArray<T> = T extends any ? T[] : never;
          type StrOrNumArray = ToArray<string | number>;
          // string[] | number[]

3. 映射类型

转换对象类型的属性:

// Partial - 所有属性可选
          type Partial<T> = {
            [P in keyof T]?: T[P];
          };
          
          // Required - 所有属性必填
          type Required<T> = {
            [P in keyof T]-?: T[P];
          };
          
          // Readonly - 所有属性只读
          type Readonly<T> = {
            readonly [P in keyof T]: T[P];
          };
          
          // Pick - 选择特定属性
          type Pick<T, K extends keyof T> = {
            [P in K]: T[P];
          };
          
          interface User {
            id: number;
            name: string;
            email: string;
            age: number;
          }
          
          type UserPreview = Pick<User, 'id' | 'name'>;
          // { id: number; name: string; }

4. 模板字面量类型

操作字符串类型:

// 字符串拼接
          type EmailAddress<T extends string> = `${T}@example.com`;
          type MyEmail = EmailAddress<'john'>; // 'john@example.com'
          
          // 事件名称生成
          type EventName<T extends string> = `on${Capitalize<T>}`;
          type ClickEvent = EventName<'click'>; // 'onClick'
          
          // CSS 属性
          type CSSProperty = 
            | 'color'
            | 'background'
            | 'padding';
          
          type CSSValue<P extends CSSProperty> = 
            P extends 'color' ? string :
            P extends 'background' ? string :
            P extends 'padding' ? number :
            never;

5. infer 关键字

在条件类型中推断类型:

// 提取函数返回类型
          type ReturnType<T> = 
            T extends (...args: any[]) => infer R ? R : never;
          
          function getUser() {
            return { name: 'John', age: 30 };
          }
          
          type User = ReturnType<typeof getUser>;
          // { name: string; age: number; }
          
          // 提取 Promise 类型
          type Unpromise<T> = 
            T extends Promise<infer R> ? R : T;
          
          type Result = Unpromise<Promise<string>>; // string
          
          // 提取数组元素类型
          type ArrayElement<T> = 
            T extends (infer E)[] ? E : T;
          
          type Item = ArrayElement<string[]>; // string

6. 递归类型

定义递归数据结构:

// 深度只读
          type DeepReadonly<T> = {
            readonly [P in keyof T]: T[P] extends object
              ? DeepReadonly<T[P]>
              : T[P];
          };
          
          // 深度可选
          type DeepPartial<T> = {
            [P in keyof T]?: T[P] extends object
              ? DeepPartial<T[P]>
              : T[P];
          };
          
          // 路径类型
          type PathOf<T> = {
            [K in keyof T]: K extends string
              ? T[K] extends object
                ? K | `${K}.${PathOf<T[K]>}`
                : K
              : never;
          }[keyof T];

7. 实用类型工具

构建可复用的类型工具:

// 提取可选属性
          type OptionalKeys<T> = {
            [K in keyof T]-?: {} extends Pick<T, K> ? K : never
          }[keyof T];
          
          // 提取必填属性
          type RequiredKeys<T> = {
            [K in keyof T]-?: {} extends Pick<T, K> ? never : K
          }[keyof T];
          
          // 函数重载类型
          type Overload<T> = T extends {
            (...args: infer A1): infer R1;
            (...args: infer A2): infer R2;
          }
            ? ((...args: A1) => R1) | ((...args: A2) => R2)
            : never;

8. 类型保护

运行时类型检查:

// 自定义类型保护
          function isString(value: unknown): value is string {
            return typeof value === 'string';
          }
          
          // 判别联合类型
          type Shape =
            | { kind: 'circle'; radius: number }
            | { kind: 'rectangle'; width: number; height: number };
          
          function getArea(shape: Shape) {
            switch (shape.kind) {
              case 'circle':
                return Math.PI * shape.radius ** 2;
              case 'rectangle':
                return shape.width * shape.height;
            }
          }

实战案例

构建类型安全的表单库:

type FormValues<T> = {
            [K in keyof T]: T[K] extends object
              ? FormValues<T[K]>
              : T[K];
          };
          
          type FormErrors<T> = {
            [K in keyof T]?: T[K] extends object
              ? FormErrors<T[K]>
              : string;
          };
          
          interface UseForm<T> {
            values: FormValues<T>;
            errors: FormErrors<T>;
            handleChange: <K extends keyof T>(field: K, value: T[K]) => void;
          }

总结

TypeScript 的高级类型系统非常强大,掌握这些技巧能让你编写更安全、更可维护的代码。持续实践是掌握这些特性的关键。

相关标签

分享文章

订阅技术周刊

每周精选优质技术文章,直接发送到你的邮箱

我们尊重你的隐私,不会发送垃圾邮件