TypeScript条件类型与映射类型高级类型编程实战

TypeScript的类型系统具备图灵完备的表达能力,条件类型映射类型是其中最强大的高级特性。在前端工程化和组件库设计中,熟练运用类型编程能构建类型安全的API接口层、自动推导工具函数类型、实现编译期参数校验。本文通过实际案例讲解条件类型、映射类型及其组合应用。

TypeScript条件类型语法与类型推断机制

条件类型的语法形式类似于JavaScript的三元表达式,根据类型关系在编译期选择不同类型分支:

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

type A = IsString<"hello">;  // true
type B = IsString<42>;      // false

infer关键字在条件类型中提取类型变量,是类型推断的核心工具。从函数类型中提取返回值类型:

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

type Fn = () => string;
type Result = ReturnType<Fn>;  // string

从Promise中提取被包裹的类型:

type Unpacked<T> = T extends Promise<infer U> ? U : T;

type Data = Unpacked<Promise<number>>;  // number

infer可以出现在多个位置,提取函数参数类型:

type Parameters<T> = T extends (...args: infer P) => any ? P : never;

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

映射类型与Key Remapping键名重写

映射类型基于已有类型生成新类型,通过in关键字遍历键名联合类型。内置的Partial、Required、Readonly、Pick均基于映射类型实现:

// Partial的实现原理
type MyPartial<T> = {
  [K in keyof T]?: T[K];
};

// Readonly的实现原理
type MyReadonly<T> = {
  readonly [K in keyof T]: T[K];
};

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

type PartialUser = MyPartial<User>;
// { name?: string; age?: number }
type ReadonlyUser = MyReadonly<User>;
// { readonly name: string; readonly age: number }

TypeScript 4.1引入Key Remapping,允许在映射过程中修改键名。结合模板字面量类型实现键名转换:

// 将所有键名转为Getter方法名
type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};

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

过滤键名生成子集类型:

// 移除指定键
type Omit<T, K extends keyof T> = {
  [P in keyof T as P extends K ? never : P]: T[P];
};

// 仅保留函数类型属性
type FunctionProperties<T> = {
  [K in keyof T as T[K] extends Function ? K : never]: T[K];
};

模板字面量类型与字符串类型操作

模板字面量类型允许在类型层面拼接和拆分字符串,配合Uppercase、Lowercase、Capitalize、Uncapitalize四个内置工具实现类型级字符串操作:

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

type ClickEvent = EventName<"click">;   // "onClick"
type FocusEvent = EventName<"focus">;  // "onFocus"

构建类型安全的事件监听器接口:

type EventMap = {
  click: { x: number; y: number };
  scroll: { scrollTop: number };
  input: { value: string };
};

type Listener<T extends keyof EventMap> = (event: EventMap[T]) => void;

function addListener<T extends keyof EventMap>(
  event: T,
  listener: Listener<T>
) {
  // 实现
}

// 类型安全:参数类型自动推导
addListener("click", (e) => {
  console.log(e.x, e.y);  // e被正确推导为{x:number;y:number}
});

路由参数类型提取:

type ExtractParams<T extends string> =
  T extends `${infer _Start}:${infer Param}/${infer Rest}`
    ? Param | ExtractParams<`/${Rest}`>
    : T extends `${infer _Start}:${infer Param}`
    ? Param
    : never;

type Route = "/users/:userId/posts/:postId";
type Params = ExtractParams<Route>;  // "userId" | "postId"

条件类型分布式特性与类型过滤

当条件类型的类型参数是裸类型参数且传入联合类型时,条件类型会分布式应用——对联合类型的每个成员分别求值后合并:

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

type Result = ToArray<string | number>;
// (string | number)[] 还是 string[] | number[]?
// 答案是 string[] | number[](分布式特性)

利用分布式特性实现类型过滤:

type Exclude<T, U> = T extends U ? never : T;

type T = Exclude<"a" | "b" | "c", "b">;  // "a" | "c"

// 从联合类型中提取指定类型
type Extract<T, U> = T extends U ? T : never;

type Strings = Extract<string | number | boolean, string>;  // string

禁用分布式特性需用方括号包裹类型参数:

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

type Result = NonDistToArray<string | number>;  // (string | number)[]

高级类型工具函数封装与复用模式

深层Partial实现,递归处理嵌套对象:

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

interface Config {
  server: {
    host: string;
    port: number;
  };
  debug: boolean;
}

type PartialConfig = DeepPartial<Config>;
// { server?: { host?: string; port?: number }; debug?: boolean }

路径类型推导,实现类型安全的对象属性访问:

type Path<T> = T extends object
  ? {
      [K in keyof T & string]: K | `${K}.${Path<T[K]>}`;
    }[keyof T & string]
  : never;

type UserPaths = Path<{ profile: { name: string; avatar: string } }>;
// "profile" | "profile.name" | "profile.avatar"

这些类型工具在组件库Props类型定义、API请求响应类型推导、状态管理Store类型约束等场景中应用广泛,能大幅减少手动类型声明的工作量,同时保证类型安全。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/typescript-tiao-jian-lei-xing-yu-ying-she-lei-xing-gao-ji/

(0)
小编小编
上一篇 10小时前
下一篇 10小时前

相关推荐