发布于

TypeScript高级类型模式:泛型、条件类型与类型体操实战

作者

TypeScript高级类型模式:泛型、条件类型与类型体操实战

TypeScript的类型系统功能强大,掌握高级类型模式能显著提升代码质量和开发体验。本文将分享TypeScript高级类型的实战技巧和最佳实践。

泛型高级应用

泛型约束与条件

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

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

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

const person = { name: 'Alice', age: 30, city: 'New York' };
const name = getProperty(person, 'name'); // string
const age = getProperty(person, 'age');   // number

// 多重泛型约束
interface Comparable<T> {
  compareTo(other: T): number;
}

interface Serializable {
  serialize(): string;
}

function processItem<T extends Comparable<T> & Serializable>(item: T): string {
  // item既可比较又可序列化
  return item.serialize();
}

// 条件泛型约束
type NonNullable<T> = T extends null | undefined ? never : T;

type Example1 = NonNullable<string | null>; // string
type Example2 = NonNullable<number | undefined>; // number

// 高级泛型工具类型
type DeepReadonly<T> = {
  readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};

interface User {
  id: number;
  profile: {
    name: string;
    settings: {
      theme: string;
      notifications: boolean;
    };
  };
}

type ReadonlyUser = DeepReadonly<User>;
// 所有属性都变为只读,包括嵌套对象

// 泛型工厂模式
interface Repository<T> {
  findById(id: string): Promise<T | null>;
  save(entity: T): Promise<T>;
  delete(id: string): Promise<void>;
}

class BaseRepository<T extends { id: string }> implements Repository<T> {
  constructor(private entityName: string) {}
  
  async findById(id: string): Promise<T | null> {
    // 实现查找逻辑
    console.log(`Finding ${this.entityName} with id: ${id}`);
    return null;
  }
  
  async save(entity: T): Promise<T> {
    console.log(`Saving ${this.entityName}:`, entity);
    return entity;
  }
  
  async delete(id: string): Promise<void> {
    console.log(`Deleting ${this.entityName} with id: ${id}`);
  }
}

// 使用示例
interface Product {
  id: string;
  name: string;
  price: number;
}

const productRepo = new BaseRepository<Product>('Product');

// 泛型单例模式
class Singleton<T> {
  private static instances: Map<any, any> = new Map();
  
  static getInstance<T>(this: new () => T): T {
    if (!Singleton.instances.has(this)) {
      Singleton.instances.set(this, new this());
    }
    return Singleton.instances.get(this);
  }
}

class DatabaseConnection extends Singleton<DatabaseConnection> {
  private constructor() {
    super();
  }
  
  connect() {
    console.log('Connected to database');
  }
}

const db1 = DatabaseConnection.getInstance();
const db2 = DatabaseConnection.getInstance();
console.log(db1 === db2); // true

高级泛型模式

// 函数重载与泛型
interface ApiResponse<T> {
  data: T;
  status: number;
  message: string;
}

// 重载签名
function apiCall<T>(url: string): Promise<ApiResponse<T>>;
function apiCall<T>(url: string, options: RequestInit): Promise<ApiResponse<T>>;
function apiCall<T, U>(url: string, options: RequestInit, transform: (data: any) => U): Promise<ApiResponse<U>>;

// 实现签名
function apiCall<T, U = T>(
  url: string, 
  options?: RequestInit, 
  transform?: (data: any) => U
): Promise<ApiResponse<T | U>> {
  return fetch(url, options)
    .then(response => response.json())
    .then(data => ({
      data: transform ? transform(data) : data,
      status: 200,
      message: 'Success'
    }));
}

// 使用示例
interface User {
  id: number;
  name: string;
}

// 基础调用
const users = await apiCall<User[]>('/api/users');

// 带选项调用
const user = await apiCall<User>('/api/users/1', { method: 'GET' });

// 带转换调用
const userNames = await apiCall(
  '/api/users',
  { method: 'GET' },
  (users: User[]) => users.map(u => u.name)
);

// 泛型类装饰器
function Entity<T extends { new(...args: any[]): {} }>(tableName: string) {
  return function(constructor: T) {
    return class extends constructor {
      tableName = tableName;
      
      save() {
        console.log(`Saving to table: ${this.tableName}`);
      }
    };
  };
}

@Entity('users')
class User {
  constructor(public name: string, public email: string) {}
}

const user = new User('Alice', 'alice@example.com');
user.save(); // Saving to table: users

// 泛型方法装饰器
function Cache<T>(ttl: number = 60000) {
  return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    const cache = new Map<string, { value: T; expiry: number }>();
    
    descriptor.value = function(...args: any[]): T {
      const key = JSON.stringify(args);
      const cached = cache.get(key);
      
      if (cached && Date.now() < cached.expiry) {
        return cached.value;
      }
      
      const result = originalMethod.apply(this, args);
      cache.set(key, { value: result, expiry: Date.now() + ttl });
      
      return result;
    };
  };
}

class DataService {
  @Cache<string[]>(30000) // 缓存30秒
  getUsers(): string[] {
    console.log('Fetching users from database...');
    return ['Alice', 'Bob', 'Charlie'];
  }
}

// 泛型事件系统
interface EventMap {
  [key: string]: any;
}

class TypedEventEmitter<T extends EventMap> {
  private listeners: { [K in keyof T]?: Array<(data: T[K]) => void> } = {};
  
  on<K extends keyof T>(event: K, listener: (data: T[K]) => void): void {
    if (!this.listeners[event]) {
      this.listeners[event] = [];
    }
    this.listeners[event]!.push(listener);
  }
  
  emit<K extends keyof T>(event: K, data: T[K]): void {
    const eventListeners = this.listeners[event];
    if (eventListeners) {
      eventListeners.forEach(listener => listener(data));
    }
  }
  
  off<K extends keyof T>(event: K, listener: (data: T[K]) => void): void {
    const eventListeners = this.listeners[event];
    if (eventListeners) {
      const index = eventListeners.indexOf(listener);
      if (index > -1) {
        eventListeners.splice(index, 1);
      }
    }
  }
}

// 定义事件类型
interface AppEvents {
  userLogin: { userId: string; timestamp: number };
  userLogout: { userId: string };
  dataUpdate: { table: string; id: string; data: any };
}

const eventEmitter = new TypedEventEmitter<AppEvents>();

// 类型安全的事件监听
eventEmitter.on('userLogin', (data) => {
  // data的类型自动推断为 { userId: string; timestamp: number }
  console.log(`User ${data.userId} logged in at ${data.timestamp}`);
});

eventEmitter.emit('userLogin', { userId: '123', timestamp: Date.now() });

条件类型深度应用

条件类型基础

// 基础条件类型
type IsString<T> = T extends string ? true : false;

type Test1 = IsString<string>; // true
type Test2 = IsString<number>; // false

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

type StringOrNumberArray = ToArray<string | number>; // string[] | number[]

// 排除类型
type Exclude<T, U> = T extends U ? never : T;
type Extract<T, U> = T extends U ? T : never;

type WithoutString = Exclude<string | number | boolean, string>; // number | boolean
type OnlyString = Extract<string | number | boolean, string>; // string

// 函数类型条件判断
type IsFunction<T> = T extends (...args: any[]) => any ? true : false;

type Test3 = IsFunction<() => void>; // true
type Test4 = IsFunction<string>; // false

// 获取函数返回类型
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

type FuncReturn = ReturnType<() => string>; // string
type AsyncFuncReturn = ReturnType<() => Promise<number>>; // Promise<number>

// 获取函数参数类型
type Parameters<T> = T extends (...args: infer P) => any ? P : never;

type FuncParams = Parameters<(a: string, b: number) => void>; // [string, number]

// 获取构造函数实例类型
type InstanceType<T> = T extends new (...args: any[]) => infer R ? R : never;

class MyClass {
  value: string = '';
}

type MyInstance = InstanceType<typeof MyClass>; // MyClass

// 深度条件类型
type DeepPartial<T> = {
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};

interface Config {
  database: {
    host: string;
    port: number;
    credentials: {
      username: string;
      password: string;
    };
  };
  cache: {
    enabled: boolean;
    ttl: number;
  };
}

type PartialConfig = DeepPartial<Config>;
// 所有属性都变为可选,包括嵌套对象

// 条件类型与映射类型结合
type PickByType<T, U> = {
  [P in keyof T as T[P] extends U ? P : never]: T[P];
};

interface Person {
  name: string;
  age: number;
  isActive: boolean;
  hobbies: string[];
}

type StringProps = PickByType<Person, string>; // { name: string }
type NumberProps = PickByType<Person, number>; // { age: number }
type ArrayProps = PickByType<Person, any[]>; // { hobbies: string[] }

高级条件类型模式

// 递归条件类型
type Flatten<T> = T extends (infer U)[] 
  ? U extends (infer V)[] 
    ? Flatten<V[]>
    : U
  : T;

type NestedArray = number[][][];
type FlatType = Flatten<NestedArray>; // number

// 字符串模板条件类型
type StartsWith<T extends string, U extends string> = T extends `${U}${string}` ? true : false;

type Test5 = StartsWith<'hello world', 'hello'>; // true
type Test6 = StartsWith<'hello world', 'world'>; // false

// 路径类型提取
type PathKeys<T> = T extends object 
  ? {
      [K in keyof T]: K extends string
        ? T[K] extends object
          ? `${K}` | `${K}.${PathKeys<T[K]>}`
          : `${K}`
        : never;
    }[keyof T]
  : never;

interface NestedObject {
  user: {
    profile: {
      name: string;
      age: number;
    };
    settings: {
      theme: string;
    };
  };
  app: {
    version: string;
  };
}

type Paths = PathKeys<NestedObject>;
// "user" | "app" | "user.profile" | "user.settings" | "user.profile.name" | "user.profile.age" | "user.settings.theme" | "app.version"

// 根据路径获取值类型
type GetByPath<T, P extends string> = P extends keyof T
  ? T[P]
  : P extends `${infer K}.${infer Rest}`
    ? K extends keyof T
      ? GetByPath<T[K], Rest>
      : never
    : never;

type UserName = GetByPath<NestedObject, 'user.profile.name'>; // string
type AppVersion = GetByPath<NestedObject, 'app.version'>; // string

// 类型安全的深度访问函数
function getByPath<T, P extends PathKeys<T>>(
  obj: T,
  path: P
): GetByPath<T, P> {
  const keys = path.split('.');
  let result: any = obj;
  
  for (const key of keys) {
    result = result[key];
  }
  
  return result;
}

const nestedObj: NestedObject = {
  user: {
    profile: { name: 'Alice', age: 30 },
    settings: { theme: 'dark' }
  },
  app: { version: '1.0.0' }
};

const userName = getByPath(nestedObj, 'user.profile.name'); // string类型,值为'Alice'
const theme = getByPath(nestedObj, 'user.settings.theme'); // string类型,值为'dark'

// 函数管道类型
type Pipe<T extends readonly any[]> = T extends readonly [
  (...args: any[]) => infer R,
  ...infer Rest
] 
  ? Rest extends readonly [(arg: R) => any, ...any[]]
    ? Pipe<Rest>
    : Rest extends readonly []
      ? R
      : never
  : never;

// 管道函数实现
function pipe<T extends readonly [(...args: any[]) => any, ...any[]]>(
  ...fns: T
): (...args: Parameters<T[0]>) => Pipe<T> {
  return (...args) => fns.reduce((acc, fn) => fn(acc), fns[0](...args));
}

// 使用示例
const add = (x: number) => x + 1;
const multiply = (x: number) => x * 2;
const toString = (x: number) => x.toString();

const pipeline = pipe(add, multiply, toString);
const result = pipeline(5); // string类型,值为'12'

// 对象键值转换
type KeyValueSwap<T extends Record<string, string | number | symbol>> = {
  [K in keyof T as T[K] extends string | number | symbol ? T[K] : never]: K;
};

type Colors = {
  red: '#ff0000';
  green: '#00ff00';
  blue: '#0000ff';
};

type ColorCodes = KeyValueSwap<Colors>;
// { '#ff0000': 'red'; '#00ff00': 'green'; '#0000ff': 'blue' }

// 联合类型转交集类型
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
  k: infer I
) => void
  ? I
  : never;

type Union = { a: string } | { b: number } | { c: boolean };
type Intersection = UnionToIntersection<Union>; // { a: string } & { b: number } & { c: boolean }

映射类型与模板字面量

映射类型高级应用

// 基础映射类型
type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};

type Partial<T> = {
  [P in keyof T]?: T[P];
};

// 条件映射类型
type NonFunctionPropertyNames<T> = {
  [K in keyof T]: T[K] extends Function ? never : K;
}[keyof T];

type NonFunctionProperties<T> = Pick<T, NonFunctionPropertyNames<T>>;

class Example {
  name: string = '';
  age: number = 0;
  getName(): string { return this.name; }
  setAge(age: number): void { this.age = age; }
}

type ExampleData = NonFunctionProperties<Example>; // { name: string; age: number }

// 属性修饰符映射
type Mutable<T> = {
  -readonly [P in keyof T]: T[P];
};

type Required<T> = {
  [P in keyof T]-?: T[P];
};

interface ReadonlyPartialUser {
  readonly name?: string;
  readonly age?: number;
}

type MutableRequiredUser = Required<Mutable<ReadonlyPartialUser>>;
// { name: string; age: number }

// 键名转换映射
type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};

type Setters<T> = {
  [K in keyof T as `set${Capitalize<string & K>}`]: (value: T[K]) => void;
};

interface User {
  name: string;
  age: number;
}

type UserGetters = Getters<User>;
// { getName: () => string; getAge: () => number }

type UserSetters = Setters<User>;
// { setName: (value: string) => void; setAge: (value: number) => void }

// 组合映射类型
type GettersAndSetters<T> = Getters<T> & Setters<T>;

type UserAccessors = GettersAndSetters<User>;
// { getName: () => string; getAge: () => number; setName: (value: string) => void; setAge: (value: number) => void }

// 实现自动生成访问器的类
function createAccessors<T extends Record<string, any>>(
  data: T
): T & GettersAndSetters<T> {
  const result = { ...data } as any;
  
  for (const key in data) {
    const capitalizedKey = key.charAt(0).toUpperCase() + key.slice(1);
    
    // 生成getter
    result[`get${capitalizedKey}`] = () => result[key];
    
    // 生成setter
    result[`set${capitalizedKey}`] = (value: any) => {
      result[key] = value;
    };
  }
  
  return result;
}

const userWithAccessors = createAccessors({ name: 'Alice', age: 30 });
console.log(userWithAccessors.getName()); // 'Alice'
userWithAccessors.setAge(31);
console.log(userWithAccessors.age); // 31

// 深度映射类型
type DeepMutable<T> = {
  -readonly [P in keyof T]: T[P] extends object ? DeepMutable<T[P]> : T[P];
};

type DeepRequired<T> = {
  [P in keyof T]-?: T[P] extends object ? DeepRequired<T[P]> : T[P];
};

interface DeepReadonlyPartial {
  readonly user?: {
    readonly profile?: {
      readonly name?: string;
      readonly age?: number;
    };
  };
}

type DeepMutableRequired = DeepRequired<DeepMutable<DeepReadonlyPartial>>;
// { user: { profile: { name: string; age: number } } }

模板字面量类型

// 基础模板字面量类型
type Greeting = `Hello, ${string}!`;

const greeting1: Greeting = 'Hello, World!'; // ✓
const greeting2: Greeting = 'Hello, TypeScript!'; // ✓
// const greeting3: Greeting = 'Hi, World!'; // ✗

// 联合类型模板
type Color = 'red' | 'green' | 'blue';
type Size = 'small' | 'medium' | 'large';

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

// 递归模板类型
type Join<T extends readonly string[], D extends string = ','>
  = T extends readonly [infer F, ...infer R]
    ? F extends string
      ? R extends readonly string[]
        ? R['length'] extends 0
          ? F
          : `${F}${D}${Join<R, D>}`
        : never
      : never
    : '';

type JoinedColors = Join<['red', 'green', 'blue'], '-'>; // 'red-green-blue'
type CsvHeader = Join<['name', 'age', 'email']>; // 'name,age,email'

// 字符串操作类型
type Split<S extends string, D extends string> = 
  S extends `${infer T}${D}${infer U}` 
    ? [T, ...Split<U, D>] 
    : [S];

type SplitPath = Split<'user.profile.name', '.'>; // ['user', 'profile', 'name']

// 驼峰命名转换
type CamelCase<S extends string> = S extends `${infer P1}_${infer P2}${infer P3}`
  ? `${P1}${Uppercase<P2>}${CamelCase<P3>}`
  : S;

type CamelCased = CamelCase<'user_profile_name'>; // 'userProfileName'

// 蛇形命名转换
type SnakeCase<S extends string> = S extends `${infer T}${infer U}`
  ? `${T extends Capitalize<T> ? '_' : ''}${Lowercase<T>}${SnakeCase<U>}`
  : S;

type SnakeCased = SnakeCase<'UserProfileName'>; // '_user_profile_name'

// URL路径类型
type Route = '/users' | '/users/:id' | '/posts' | '/posts/:id/comments';

type ExtractParams<T extends string> = T extends `${string}:${infer Param}/${infer Rest}`
  ? { [K in Param]: string } & ExtractParams<`/${Rest}`>
  : T extends `${string}:${infer Param}`
    ? { [K in Param]: string }
    : {};

type UserRouteParams = ExtractParams<'/users/:id'>; // { id: string }
type CommentRouteParams = ExtractParams<'/posts/:id/comments'>; // { id: string }

// 类型安全的路由函数
function createRoute<T extends string>(
  path: T
): (params: ExtractParams<T>) => string {
  return (params) => {
    let result = path;
    for (const [key, value] of Object.entries(params)) {
      result = result.replace(`:${key}`, value);
    }
    return result;
  };
}

const userRoute = createRoute('/users/:id');
const userUrl = userRoute({ id: '123' }); // '/users/123'

const commentRoute = createRoute('/posts/:postId/comments/:commentId');
const commentUrl = commentRoute({ postId: '456', commentId: '789' });
// '/posts/456/comments/789'

实用工具类型

自定义工具类型

// 可选属性工具类型
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];

interface MixedInterface {
  required: string;
  optional?: number;
  alsoOptional?: boolean;
}

type OptionalProps = OptionalKeys<MixedInterface>; // 'optional' | 'alsoOptional'
type RequiredProps = RequiredKeys<MixedInterface>; // 'required'

// 类型合并工具
type Merge<T, U> = {
  [K in keyof T | keyof U]: K extends keyof U
    ? U[K]
    : K extends keyof T
      ? T[K]
      : never;
};

type A = { a: string; b: number };
type B = { b: string; c: boolean };
type Merged = Merge<A, B>; // { a: string; b: string; c: boolean }

// 深度合并类型
type DeepMerge<T, U> = {
  [K in keyof T | keyof U]: K extends keyof U
    ? K extends keyof T
      ? T[K] extends object
        ? U[K] extends object
          ? DeepMerge<T[K], U[K]>
          : U[K]
        : U[K]
      : U[K]
    : K extends keyof T
      ? T[K]
      : never;
};

// 数组类型工具
type Head<T extends readonly any[]> = T extends readonly [infer H, ...any[]] ? H : never;
type Tail<T extends readonly any[]> = T extends readonly [any, ...infer R] ? R : [];
type Last<T extends readonly any[]> = T extends readonly [...any[], infer L] ? L : never;

type FirstElement = Head<[1, 2, 3]>; // 1
type RestElements = Tail<[1, 2, 3]>; // [2, 3]
type LastElement = Last<[1, 2, 3]>; // 3

// 元组长度类型
type Length<T extends readonly any[]> = T['length'];

type ArrayLength = Length<[1, 2, 3, 4, 5]>; // 5

// 元组反转类型
type Reverse<T extends readonly any[]> = T extends readonly [...infer Rest, infer Last]
  ? [Last, ...Reverse<Rest>]
  : [];

type Reversed = Reverse<[1, 2, 3, 4]>; // [4, 3, 2, 1]

// 函数组合类型
type Compose<F extends readonly any[]> = F extends readonly [
  (...args: any[]) => infer R,
  ...infer Rest
]
  ? Rest extends readonly [any, ...any[]]
    ? Rest extends readonly [(arg: R) => any, ...any[]]
      ? Compose<Rest>
      : never
    : R
  : never;

// 实现compose函数
function compose<T extends readonly [(...args: any[]) => any, ...any[]]>(
  ...fns: T
): (...args: Parameters<T[0]>) => Compose<T> {
  return (...args) => fns.reduceRight((acc, fn) => fn(acc), fns[0](...args));
}

// Promise工具类型
type PromiseValue<T> = T extends Promise<infer U> ? U : T;
type PromiseValues<T extends readonly any[]> = {
  [K in keyof T]: PromiseValue<T[K]>;
};

type SinglePromise = PromiseValue<Promise<string>>; // string
type MultiplePromises = PromiseValues<[Promise<string>, Promise<number>, boolean]>; 
// [string, number, boolean]

// 异步函数类型工具
type AsyncReturnType<T extends (...args: any[]) => Promise<any>> = 
  T extends (...args: any[]) => Promise<infer R> ? R : never;

async function fetchUser(): Promise<{ id: number; name: string }> {
  return { id: 1, name: 'Alice' };
}

type UserType = AsyncReturnType<typeof fetchUser>; // { id: number; name: string }

// 类型守卫工具
type TypeGuard<T> = (value: any) => value is T;

function createTypeGuard<T>(validator: (value: any) => boolean): TypeGuard<T> {
  return (value: any): value is T => validator(value);
}

const isString = createTypeGuard<string>(value => typeof value === 'string');
const isNumber = createTypeGuard<number>(value => typeof value === 'number');

function processValue(value: unknown) {
  if (isString(value)) {
    // value的类型现在是string
    console.log(value.toUpperCase());
  } else if (isNumber(value)) {
    // value的类型现在是number
    console.log(value.toFixed(2));
  }
}

总结

TypeScript高级类型的核心要点:

  1. 泛型约束:使用extends关键字限制泛型类型
  2. 条件类型:基于类型条件进行类型推断和转换
  3. 映射类型:遍历和转换对象类型的属性
  4. 模板字面量:类型级别的字符串操作和模式匹配
  5. 工具类型:构建可复用的类型操作工具

掌握这些高级类型模式能够让我们编写更加类型安全、可维护的TypeScript代码,充分发挥TypeScript类型系统的威力。