TypeScript 高级类型:条件类型、映射类型与模板字面量类型

详解 TypeScript 高级类型系统:条件类型(Conditional Types)、映射类型(Mapped Types)、模板字面量类型(Template Literal Types)、 keyof/infer、类型体操实用场景。含 10+ 个可直接复用的类型工具。

TypeScript 的类型系统是一门图灵完备的语言:它支持条件分支、循环(递归)、变量声明(泛型),可以表达极其复杂的类型关系。本文从实用角度讲解高级类型,提供可直接复用的类型工具。


一、条件类型(Conditional Types)

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

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

infer 关键字(类型提取)

// 提取 Promise 的返回值类型
type Awaited<T> = T extends Promise<infer R> ? R : T;
type Result = Awaited<Promise<string>>; // string

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

// 提取数组元素类型
type ElementType<T> = T extends Array<infer E> ? E : never;
type E = ElementType<string[]>; // string

二、映射类型(Mapped Types)

// 把所有属性变为可选
type Partial<T> = {
  [K in keyof T]?: T[K];
};

// 把所有属性变为只读
type Readonly<T> = {
  readonly [K in keyof T]: T[K];
};

// 只保留指定属性
type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
};

// 自定义:把对象的所有值转为 string
type Stringify<T> = {
  [K in keyof T]: string;
};

interface User {
  name: string;
  age: number;
}
type StringUser = Stringify<User>;
// { name: string; age: string; }

三、模板字面量类型

type EventName<T extends string> = `on${Capitalize<T>}`;
type ClickEvent = EventName<'click'>; // 'onClick'

// 生成 CSS margin/padding 工具类类型
type Spacing = 'xs' | 'sm' | 'md' | 'lg';
type MarginClass = `m-${Spacing}` | `mx-${Spacing}` | `my-${Spacing}`;
// 'm-xs' | 'm-sm' | 'mx-xs' | 'mx-sm' | ...

四、实用类型工具集

// 1. DeepPartial — 递归可选
type DeepPartial<T> = {
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};

// 2. RequiredBy — 只让部分属性必填
type RequiredBy<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;

// 3. NonNullableProperties — 移除所有 null/undefined
type NonNullableProperties<T> = {
  [K in keyof T]: NonNullable<T[K]>;
};

// 4. Flatten — 拍平嵌套对象
type Flatten<T> = T extends object ? { [K in keyof T]: T[K] } : T;

// 5. UnionToIntersection — 联合转交叉
type UnionToIntersection<U> = (
  U extends any ? (k: U) => void : never
) extends (k: infer I) => void ? I : never;

相关阅读

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「frontend」更多文章