阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 复杂泛型类型解析

复杂泛型类型解析

作者:陈川 阅读数:62766人阅读 分类: TypeScript

复杂泛型类型解析

TypeScript的泛型系统允许开发者创建可重用的组件,同时保持类型安全。当泛型类型开始嵌套和组合时,类型解析变得复杂但功能强大。理解这些复杂泛型类型的解析机制,能够帮助开发者构建更灵活的类型系统。

基础泛型回顾

泛型的基础形式是使用类型参数:

function identity<T>(arg: T): T {
  return arg;
}

当这个函数被调用时,TypeScript会自动推断类型参数:

let output = identity<string>("hello");  // 显式指定
let output2 = identity("hello");         // 自动推断为string

泛型约束

通过extends关键字可以约束泛型参数:

interface Lengthwise {
  length: number;
}

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

条件类型

条件类型是泛型类型解析中的关键特性:

type IsString<T> = T extends string ? true : false;

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

分布式条件类型

当条件类型作用于联合类型时,会进行分布式解析:

type ToArray<T> = T extends any ? T[] : never;

type StrOrNumArray = ToArray<string | number>;  
// 解析为 string[] | number[]

类型推断infer

infer关键字可以在条件类型中声明类型变量:

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;

type FnReturn = ReturnType<() => number>;  // number

映射类型

映射类型可以基于旧类型创建新类型:

type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};

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

type ReadonlyPerson = Readonly<Person>;

递归类型

TypeScript支持递归类型定义:

type JsonValue = 
  | string 
  | number 
  | boolean 
  | null 
  | JsonValue[] 
  | { [key: string]: JsonValue };

const json: JsonValue = {
  name: "John",
  age: 30,
  hobbies: ["reading", { type: "sports", frequency: "daily" }]
};

模板字面量类型

结合泛型可以创建强大的字符串类型:

type EventName<T extends string> = `${T}Changed`;

type Concat<A extends string, B extends string> = `${A}${B}`;

type T0 = EventName<'foo'>;  // 'fooChanged'
type T1 = Concat<'Hello', 'World'>;  // 'HelloWorld'

复杂泛型示例解析

解析一个复杂的实用类型:

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

interface User {
  id: number;
  info: {
    name: string;
    age: number;
    address: {
      city: string;
      country: string;
    };
  };
}

type PartialUser = DeepPartial<User>;
/* 等价于:
{
  id?: number;
  info?: {
    name?: string;
    age?: number;
    address?: {
      city?: string;
      country?: string;
    };
  };
}
*/

类型编程技巧

结合多个高级特性创建实用类型:

type GetProps<T> = 
  T extends React.ComponentType<infer P> ? P : never;

type ExtractState<T> = 
  T extends React.Component<infer P, infer S> ? S : never;

type PromiseValue<T> = 
  T extends Promise<infer V> ? V : T;

类型兼容性检查

使用条件类型检查类型兼容性:

type IsAssignable<T, U> = T extends U ? true : false;

type T1 = IsAssignable<number, string | number>;  // true
type T2 = IsAssignable<string, number>;          // false

泛型工具类型进阶

创建更复杂的工具类型:

type Nullable<T> = T | null;
type NonNullable<T> = T extends null | undefined ? never : T;

type Flatten<T> = T extends Array<infer U> ? Flatten<U> : T;

type T3 = Flatten<number[][]>;  // number

类型级编程挑战

解决实际的类型编程问题:

type Join<T extends string[], D extends string> =
  T extends [] ? '' :
  T extends [infer F] ? F :
  T extends [infer F, ...infer R] ?
    F extends string ?
      R extends string[] ?
        `${F}${D}${Join<R, D>}` : never : never : never;

type T4 = Join<['a', 'b', 'c'], '-'>;  // 'a-b-c'

类型系统边界探索

探索TypeScript类型系统的极限:

type Fibonacci<T extends number, N1 extends number = 1, N2 extends number = 1> =
  T extends 0 ? 0 :
  T extends 1 | 2 ? 1 :
  T extends number ? Fibonacci<Subtract<T, 1>, N2, Add<N1, N2>> : never;

// 需要定义Add和Subtract类型
type Add<A extends number, B extends number> = [...Array<A>, ...Array<B>]['length'];
type Subtract<A extends number, B extends number> = 
  Array<A> extends [...Array<B>, ...infer R] ? R['length'] : never;

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:泛型性能考量

下一篇:泛型设计模式

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌