1. Generic Functions
Generics let you write reusable, type-safe components. Type parameters are declared with angle brackets and can be explicitly specified or automatically inferred by the compiler:
// 基本泛型函数
function identity<T>(arg: T): T {
return arg;
}
// 显式指定类型参数
const str = identity<string>("hello");
// 类型推断——编译器自动推导 T = number
const num = identity(42);
// 多个类型参数
function pair<A, B>(first: A, second: B): [A, B] {
return [first, second];
}
const p = pair("age", 30); // 推断为 [string, number]
// 泛型箭头函数
const toArray = <T,>(value: T): T[] => [value];
Note the comma in <T,> for arrow functions — in .tsx files this comma is needed to avoid confusion with JSX tags.
2. Generic Interfaces and Classes
// 泛型接口
interface Container<T> {
value: T;
getValue(): T;
}
const numBox: Container<number> = {
value: 42,
getValue() { return this.value; }
};
// 泛型类——实现一个类型安全的栈
class Stack<T> {
private items: T[] = [];
push(item: T): void { this.items.push(item); }
pop(): T | undefined { return this.items.pop(); }
peek(): T | undefined { return this.items[this.items.length - 1]; }
get size(): number { return this.items.length; }
}
const numberStack = new Stack<number>();
numberStack.push(1);
numberStack.push(2);
// numberStack.push("3"); // ✗ 编译错误
3. Generic Constraints
Use the extends keyword to constrain type parameters, ensuring generics meet certain conditions:
interface HasLength {
length: number;
}
// T 必须有 length 属性
function logLength<T extends HasLength>(arg: T): number {
console.log(arg.length);
return arg.length;
}
logLength("hello"); // ✓ string 有 length
logLength([1, 2, 3]); // ✓ 数组有 length
// logLength(123); // ✗ number 没有 length
// keyof 约束——限制 key 必须是 obj 的属性名
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user = { name: "Alice", age: 30 };
getProperty(user, "name"); // ✓ 返回 string
// getProperty(user, "email"); // ✗ "email" 不在 keyof typeof user 中
4. Common Utility Types
TypeScript includes many built-in utility types. Mastering them can significantly reduce boilerplate code:
interface User {
id: number;
name: string;
email: string;
age: number;
}
// Partial<T> —— 所有属性变为可选
type UpdateUser = Partial<User>;
// { id?: number; name?: string; email?: string; age?: number }
// Required<T> —— 所有属性变为必填
type StrictUser = Required<Partial<User>>;
// Pick<T, K> —— 选取部分属性
type UserSummary = Pick<User, "id" | "name">;
// { id: number; name: string }
// Omit<T, K> —— 排除部分属性
type UserWithoutEmail = Omit<User, "email">;
// Record<K, V> —— 构造键值对类型
type RolePermissions = Record<"admin" | "user" | "guest", string[]>;
// Readonly<T> —— 所有属性变为只读
type FrozenUser = Readonly<User>;
// ReturnType<T> / Parameters<T>
function createUser(name: string, age: number) { return { name, age }; }
type Created = ReturnType<typeof createUser>; // { name: string; age: number }
type Args = Parameters<typeof createUser>; // [string, number]
5. Conditional Types
Conditional types let you do if/else at the type level, with syntax similar to ternary expressions:
// 基本语法:T extends U ? X : Y
type IsString<T> = T extends string ? "yes" : "no";
type A = IsString<string>; // "yes"
type B = IsString<number>; // "no"
// 内置条件类型的实现原理
type MyNonNullable<T> = T extends null | undefined ? never : T;
type C = MyNonNullable<string | null>; // string
type MyExtract<T, U> = T extends U ? T : never;
type D = MyExtract<"a" | "b" | "c", "a" | "c">; // "a" | "c"
type MyExclude<T, U> = T extends U ? never : T;
type E = MyExclude<"a" | "b" | "c", "a">; // "b" | "c"
Union types in conditional types distribute automatically — T extends U ? X : Y evaluates separately for each member of the union, then merges the results.
6. Mapped Types
// 映射类型:遍历已有类型的键来创建新类型
type MyReadonly<T> = {
readonly [K in keyof T]: T[K];
};
type MyPartial<T> = {
[K in keyof T]?: T[K];
};
// 自定义映射类型——将所有属性值变为 Promise
type Async<T> = {
[K in keyof T]: Promise<T[K]>;
};
interface SyncAPI {
getUser(): User;
getAge(): number;
}
type AsyncAPI = Async<SyncAPI>;
// { getUser(): Promise<User>; getAge(): Promise<number> }
// 键的重映射(as 子句)
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
type UserGetters = Getters<User>;
// { getId: () => number; getName: () => string; ... }
7. Template Literal Types
// 模板字面量类型——在类型层面拼接字符串
type EventName = `on${string}`;
const e1: EventName = "onClick"; // ✓
// const e2: EventName = "click"; // ✗ 缺少 "on" 前缀
// 结合联合类型,生成所有组合
type Color = "red" | "blue";
type Size = "small" | "large";
type Style = `${Color}-${Size}`;
// "red-small" | "red-large" | "blue-small" | "blue-large"
// 内置字符串操作类型
type Upper = Uppercase<"hello">; // "HELLO"
type Lower = Lowercase<"HELLO">; // "hello"
type Cap = Capitalize<"hello">; // "Hello"
type Uncap = Uncapitalize<"Hello">; // "hello"
8. The infer Keyword
infer declares a type variable to be inferred within conditional types, letting you extract sub-types from complex types:
// 提取函数返回类型(ReturnType 的实现原理)
type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type R1 = MyReturnType<() => string>; // string
type R2 = MyReturnType<(x: number) => void>; // void
// 提取函数参数类型
type MyParameters<T> = T extends (...args: infer P) => any ? P : never;
type P1 = MyParameters<(a: string, b: number) => void>; // [string, number]
// 提取 Promise 包裹的类型
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
type V1 = UnwrapPromise<Promise<string>>; // string
type V2 = UnwrapPromise<number>; // number
// 提取数组元素类型
type ElementOf<T> = T extends (infer E)[] ? E : never;
type El = ElementOf<string[]>; // string
📝 Chapter Summary
- ✦Generics are the foundation for writing reusable, type-safe code — functions, interfaces, and classes can all use generics
- ✦Use
extendsto constrain generic parameters, usekeyofto get the union type of object keys - ✦Mastering built-in Utility Types (Partial, Pick, Omit, Record, etc.) can greatly improve development efficiency
- ✦Conditional types +
inferare the core of advanced type programming, enabling extraction and transformation of information from existing types - ✦Mapped types and template literal types let you batch-generate and transform types, enabling powerful type abstractions