4.1 泛型编程
4.1.1 泛型基础
泛型允许我们创建可重用的组件,这些组件可以处理多种类型而不是单一类型。
// 基本泛型函数
function identity<T>(arg: T): T {
return arg;
}
// 使用泛型函数
let output1 = identity<string>("myString");
let output2 = identity<number>(100);
// 类型推断
let output3 = identity("myString"); // TypeScript 自动推断为 string
4.1.2 泛型约束
使用 extends
关键字来约束泛型类型:
// 基本约束
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // 现在我们知道它有 length 属性
return arg;
}
// 使用约束
loggingIdentity("hello"); // 字符串有 length 属性
loggingIdentity([1, 2, 3]); // 数组有 length 属性
// loggingIdentity(3); // 错误:number 没有 length 属性
// 在泛型约束中使用类型参数
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
let person = { name: "Alice", age: 30, city: "New York" };
let name = getProperty(person, "name"); // string
let age = getProperty(person, "age"); // number
// let invalid = getProperty(person, "salary"); // 错误:参数类型不匹配
4.1.3 泛型类
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
constructor(zeroValue: T, addFn: (x: T, y: T) => T) {
this.zeroValue = zeroValue;
this.add = addFn;
}
}
// 数字版本
let myGenericNumber = new GenericNumber<number>(0, (x, y) => x + y);
console.log(myGenericNumber.add(5, 10)); // 15
// 字符串版本
let myGenericString = new GenericNumber<string>("", (x, y) => x + y);
console.log(myGenericString.add("Hello ", "World")); // "Hello World"
4.1.4 泛型接口
// 泛型接口
interface GenericIdentityFn<T> {
(arg: T): T;
}
function identity<T>(arg: T): T {
return arg;
}
let myIdentity: GenericIdentityFn<number> = identity;
// 更复杂的泛型接口
interface Repository<T> {
findById(id: string): T | undefined;
save(entity: T): void;
delete(id: string): boolean;
findAll(): T[];
}
class UserRepository implements Repository<User> {
private users: User[] = [];
findById(id: string): User | undefined {
return this.users.find(user => user.id === id);
}
save(user: User): void {
this.users.push(user);
}
delete(id: string): boolean {
const index = this.users.findIndex(user => user.id === id);
if (index > -1) {
this.users.splice(index, 1);
return true;
}
return false;
}
findAll(): User[] {
return [...this.users];
}
}
4.2 条件类型
4.2.1 基本条件类型
条件类型的语法:T extends U ? X : Y
// 基本条件类型
type IsString<T> = T extends string ? true : false;
type Test1 = IsString<string>; // true
type Test2 = IsString<number>; // false
type Test3 = IsString<"hello">; // true
// 更实用的例子
type NonNullable<T> = T extends null | undefined ? never : T;
type Test4 = NonNullable<string | null>; // string
type Test5 = NonNullable<number | undefined>; // number
type Test6 = NonNullable<boolean | null | undefined>; // boolean
4.2.2 分布式条件类型
当条件类型作用于联合类型时,会分布到每个成员:
type ToArray<T> = T extends any ? T[] : never;
type Test7 = ToArray<string | number>; // string[] | number[]
// 实用工具类型
type Exclude<T, U> = T extends U ? never : T;
type Extract<T, U> = T extends U ? T : never;
type Test8 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
type Test9 = Extract<"a" | "b" | "c", "a" | "f">; // "a"
4.2.3 条件类型中的类型推断
使用 infer
关键字在条件类型中推断类型:
// 推断返回类型
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
type Test10 = ReturnType<() => string>; // string
type Test11 = ReturnType<(x: number) => number>; // number
// 推断数组元素类型
type ArrayElementType<T> = T extends (infer U)[] ? U : never;
type Test12 = ArrayElementType<string[]>; // string
type Test13 = ArrayElementType<number[]>; // number
// 推断 Promise 的值类型
type PromiseType<T> = T extends Promise<infer U> ? U : never;
type Test14 = PromiseType<Promise<string>>; // string
type Test15 = PromiseType<Promise<number>>; // number
4.3 映射类型
4.3.1 基本映射类型
映射类型允许我们基于旧类型创建新类型:
// 基本映射类型语法
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
type Partial<T> = {
[P in keyof T]?: T[P];
};
type Required<T> = {
[P in keyof T]-?: T[P];
};
// 使用示例
interface User {
id: string;
name: string;
email?: string;
}
type ReadonlyUser = Readonly<User>;
// {
// readonly id: string;
// readonly name: string;
// readonly email?: string;
// }
type PartialUser = Partial<User>;
// {
// id?: string;
// name?: string;
// email?: string;
// }
type RequiredUser = Required<User>;
// {
// id: string;
// name: string;
// email: string; // 注意:不再是可选的
// }
4.3.2 高级映射类型
// Pick:选择特定属性
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
type UserBasicInfo = Pick<User, "id" | "name">;
// {
// id: string;
// name: string;
// }
// Omit:排除特定属性
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
type UserWithoutId = Omit<User, "id">;
// {
// name: string;
// email?: string;
// }
// Record:创建具有特定键和值类型的对象类型
type Record<K extends keyof any, T> = {
[P in K]: T;
};
type UserRoles = Record<"admin" | "user" | "guest", boolean>;
// {
// admin: boolean;
// user: boolean;
// guest: boolean;
// }
4.3.3 键重映射
TypeScript 4.1+ 支持键重映射:
// 键重映射语法
type MappedTypeWithNewProperties<T> = {
[Properties in keyof T as NewKeyType]: T[Properties]
}
// 示例:添加前缀
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]
};
type UserGetters = Getters<User>;
// {
// getId: () => string;
// getName: () => string;
// getEmail: () => string | undefined;
// }
// 过滤属性
type RemoveKindField<T> = {
[K in keyof T as K extends "kind" ? never : K]: T[K]
};
interface Circle {
kind: "circle";
radius: number;
}
type KindlessCircle = RemoveKindField<Circle>;
// {
// radius: number;
// }
4.4 模板字面量类型
4.4.1 基本模板字面量类型
TypeScript 4.1+ 引入了模板字面量类型:
// 基本模板字面量类型
type World = "world";
type Greeting = `hello ${World}`; // "hello world"
// 与联合类型结合
type EmailLocaleIDs = "welcome_email" | "email_heading";
type FooterLocaleIDs = "footer_title" | "footer_sendoff";
type AllLocaleIDs = `${EmailLocaleIDs | FooterLocaleIDs}_id`;
// "welcome_email_id" | "email_heading_id" | "footer_title_id" | "footer_sendoff_id"
4.4.2 内置字符串操作类型
// 内置字符串操作类型
type Uppercase<S extends string> = intrinsic;
type Lowercase<S extends string> = intrinsic;
type Capitalize<S extends string> = intrinsic;
type Uncapitalize<S extends string> = intrinsic;
// 使用示例
type LoudGreeting = Uppercase<"Hello World">; // "HELLO WORLD"
type QuietGreeting = Lowercase<"Hello World">; // "hello world"
type CapitalizedGreeting = Capitalize<"hello world">; // "Hello world"
type UncapitalizedGreeting = Uncapitalize<"Hello World">; // "hello World"
// 实际应用:创建事件处理器类型
type ObjectWithOnMethods<T> = {
[K in keyof T as `on${Capitalize<string & K>}`]: (value: T[K]) => void;
};
interface Person {
name: string;
age: number;
}
type PersonEventHandlers = ObjectWithOnMethods<Person>;
// {
// onName: (value: string) => void;
// onAge: (value: number) => void;
// }
4.4.3 模板字面量类型的实际应用
// CSS 属性类型
type CSSProperties = {
[K in
| "margin"
| "padding"
| "border" as K | `${K}Top` | `${K}Right` | `${K}Bottom` | `${K}Left`]?: string;
};
// 使用
const styles: CSSProperties = {
margin: "10px",
marginTop: "5px",
padding: "20px",
paddingLeft: "15px"
};
// API 路径类型
type APIPath<T extends string> = `/api/${T}`;
type UserAPIPath = APIPath<"users">; // "/api/users"
type ProductAPIPath = APIPath<"products">; // "/api/products"
// 数据库查询构建器
type QueryBuilder<T> = {
[K in keyof T as `findBy${Capitalize<string & K>}`]: (value: T[K]) => T[];
};
type UserQueries = QueryBuilder<User>;
// {
// findById: (value: string) => User[];
// findByName: (value: string) => User[];
// findByEmail: (value: string | undefined) => User[];
// }
4.5 实用工具类型
4.5.1 内置工具类型总结
// 基础工具类型
type Partial<T> = { [P in keyof T]?: T[P] };
type Required<T> = { [P in keyof T]-?: T[P] };
type Readonly<T> = { readonly [P in keyof T]: T[P] };
type Record<K extends keyof any, T> = { [P in K]: T };
// 选择和排除
type Pick<T, K extends keyof T> = { [P in K]: T[P] };
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
type Exclude<T, U> = T extends U ? never : T;
type Extract<T, U> = T extends U ? T : never;
// 空值处理
type NonNullable<T> = T extends null | undefined ? never : T;
// 函数类型
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
type ConstructorParameters<T extends abstract new (...args: any) => any> = T extends abstract new (...args: infer P) => any ? P : never;
type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;
4.5.2 自定义工具类型
// 深度只读
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};
// 深度可选
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};
// 获取函数参数的第一个类型
type Head<T extends any[]> = T extends [infer H, ...any[]] ? H : never;
// 获取函数参数的尾部类型
type Tail<T extends any[]> = T extends [any, ...infer T] ? T : [];
// 判断类型是否相等
type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false;
// 使用示例
interface NestedUser {
id: string;
profile: {
name: string;
settings: {
theme: string;
notifications: boolean;
};
};
}
type ReadonlyNestedUser = DeepReadonly<NestedUser>;
type PartialNestedUser = DeepPartial<NestedUser>;
type FirstParam = Head<[string, number, boolean]>; // string
type RestParams = Tail<[string, number, boolean]>; // [number, boolean]
type IsEqual = Equal<string, string>; // true
type IsNotEqual = Equal<string, number>; // false
4.6 类型编程实战
4.6.1 构建类型安全的状态管理
// 状态管理类型定义
type Action<T extends string, P = {}> = {
type: T;
} & P;
type ActionCreator<T extends string, P = {}> = P extends {}
? () => Action<T, P>
: (payload: P) => Action<T, P>;
// 状态和动作定义
interface AppState {
user: User | null;
loading: boolean;
error: string | null;
}
type UserActions =
| Action<"SET_USER", { payload: User }>
| Action<"CLEAR_USER">
| Action<"SET_LOADING", { payload: boolean }>
| Action<"SET_ERROR", { payload: string }>;
// 类型安全的 reducer
type Reducer<S, A> = (state: S, action: A) => S;
const userReducer: Reducer<AppState, UserActions> = (state, action) => {
switch (action.type) {
case "SET_USER":
return { ...state, user: action.payload, error: null };
case "CLEAR_USER":
return { ...state, user: null };
case "SET_LOADING":
return { ...state, loading: action.payload };
case "SET_ERROR":
return { ...state, error: action.payload };
default:
return state;
}
};
4.6.2 构建类型安全的 API 客户端
// API 端点定义
interface APIEndpoints {
"/users": {
GET: { response: User[] };
POST: { body: Omit<User, "id">; response: User };
};
"/users/:id": {
GET: { params: { id: string }; response: User };
PUT: { params: { id: string }; body: Partial<User>; response: User };
DELETE: { params: { id: string }; response: void };
};
}
// 提取路径参数
type ExtractParams<T extends string> =
T extends `${infer _Start}:${infer Param}/${infer Rest}`
? { [K in Param]: string } & ExtractParams<`/${Rest}`>
: T extends `${infer _Start}:${infer Param}`
? { [K in Param]: string }
: {};
// API 客户端类型
type APIClient = {
[Path in keyof APIEndpoints]: {
[Method in keyof APIEndpoints[Path]]: (
...args: APIEndpoints[Path][Method] extends { params: infer P; body: infer B }
? [params: P, body: B]
: APIEndpoints[Path][Method] extends { params: infer P }
? [params: P]
: APIEndpoints[Path][Method] extends { body: infer B }
? [body: B]
: []
) => Promise<APIEndpoints[Path][Method] extends { response: infer R } ? R : void>;
};
};
// 使用示例
declare const apiClient: APIClient;
// 类型安全的 API 调用
apiClient["/users"].GET(); // Promise<User[]>
apiClient["/users"].POST({ name: "Alice", email: "alice@example.com" }); // Promise<User>
apiClient["/users/:id"].GET({ id: "123" }); // Promise<User>
apiClient["/users/:id"].PUT({ id: "123" }, { name: "Bob" }); // Promise<User>
4.7 本章练习
练习 1:泛型工具函数
实现以下泛型工具函数:
// 1. 实现一个泛型函数,用于深度克隆对象
function deepClone<T>(obj: T): T {
// 你的实现
}
// 2. 实现一个泛型函数,用于合并两个对象
function merge<T, U>(obj1: T, obj2: U): T & U {
// 你的实现
}
// 3. 实现一个泛型函数,用于获取对象的键值对数组
function entries<T>(obj: T): Array<[keyof T, T[keyof T]]> {
// 你的实现
}
练习 2:高级类型操作
实现以下类型操作:
// 1. 实现一个类型,将对象的所有属性变为可选,但保持嵌套对象的结构
type DeepPartial<T> = {
// 你的实现
};
// 2. 实现一个类型,获取对象中所有函数类型的属性名
type FunctionPropertyNames<T> = {
// 你的实现
};
// 3. 实现一个类型,将联合类型转换为交叉类型
type UnionToIntersection<U> = {
// 你的实现
};
练习 3:实际应用
构建一个类型安全的表单验证系统:
// 定义表单字段类型
interface FormField<T> {
value: T;
error?: string;
validators: Array<(value: T) => string | undefined>;
}
// 定义表单类型
type Form<T> = {
[K in keyof T]: FormField<T[K]>;
};
// 实现表单验证函数
function validateForm<T>(form: Form<T>): boolean {
// 你的实现
}
// 使用示例
interface UserForm {
name: string;
email: string;
age: number;
}
const userForm: Form<UserForm> = {
// 你的实现
};
4.8 本章总结
本章深入探讨了 TypeScript 的高级类型系统,包括:
- 泛型编程:学习了泛型函数、泛型类、泛型接口和泛型约束
- 条件类型:掌握了条件类型的语法、分布式条件类型和类型推断
- 映射类型:了解了如何基于现有类型创建新类型,包括键重映射
- 模板字面量类型:学习了字符串模板类型和内置字符串操作
- 实用工具类型:掌握了内置工具类型和自定义工具类型的创建
- 类型编程实战:通过实际案例学习了高级类型系统的应用
这些高级类型特性使 TypeScript 能够提供强大的类型安全保障,同时保持代码的灵活性和可维护性。掌握这些概念对于编写高质量的 TypeScript 代码至关重要。
下一章我们将学习模块系统和命名空间,了解如何组织和管理大型 TypeScript 项目的代码结构。