在 TypeScript 中,高级类型(Advanced Types)是一组强大的工具,能够帮助你创建更精确、灵活和可维护的类型定义。这些类型超越了基本的接口和类型别名,提供了组合、转换和操作类型的先进方法。本文将深入探讨 TypeScript 中最实用的高级类型及其实际应用场景。
1. 联合类型(Union Types)
联合类型允许一个值可以属于多种类型中的一种,使用 | 运算符表示:
type Status = 'pending' | 'success' | 'error';
function handleResponse(status: Status) {
// 根据不同的状态值进行处理
}
// 应用示例:函数参数可以是多种类型
function formatInput(input: string | number | Date) {
if (typeof input === 'string') {
return input.trim();
}
if (input instanceof Date) {
return input.toISOString();
}
return input.toFixed(2);
}
实用场景:
- 表示可能的状态值
- 处理多种输入类型
- 替代枚举类型的轻量级方案
2. 交叉类型(Intersection Types)
交叉类型使用 & 运算符组合多个类型,创建一个包含所有类型特性的新类型:
interface Person {
name: string;
age: number;
}
interface Employee {
employeeId: number;
department: string;
}
type Staff = Person & Employee;
const staffMember: Staff = {
name: 'Alice Zhang',
age: 32,
employeeId: 1001,
department: 'Engineering'
};
// 实用例子:扩展函数选项
type DataFetchOptions = { timeout: number } & RequestInit;
async function fetchData(url: string, options: DataFetchOptions) {
return fetch(url, {
...options,
timeout: options.timeout || 5000
});
}
3. 类型别名(Type Aliases)
类型别名为你复杂的类型创建新名称,提高代码可读性:
// 基本类型别名
type ID = string | number;
type Callback<T> = (result: T) => void;
// 复杂类型别名
type Coordinate = {
x: number;
y: number;
z?: number; // 可选属性
};
type Point3D = Coordinate & { z: number };
// 实用示例:简化复杂类型
type UserProfile = {
id: ID;
name: string;
email: string;
preferences: {
theme: 'light' | 'dark';
notifications: boolean;
};
};
function updateProfile(profile: Partial<UserProfile>) {
// 部分更新用户配置
}
4. 索引类型和映射类型(Index and Mapped Types)
TypeScript 提供了根据已知类型创建新类型的映射能力:
基本映射类型
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 {
name: string;
email?: string;
}
const readOnlyUser: Readonly<User> = {
name: 'Bob',
email: 'bob@example.com'
};
// readOnlyUser.name = 'Alice'; // 错误:只读属性
const partialUser: Partial<User> = {
email: 'updated@example.com' // 只提供部分属性
};
高级映射类型:键重映射
// 添加getter方法
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
interface Person {
name: string;
age: number;
}
type PersonGetters = Getters<Person>;
// 等价于:
// {
// getName: () => string;
// getAge: () => number;
// }
// 过滤特定属性
type OnlyMethods<T> = {
[K in keyof T as T[K] extends Function ? K : never]: T[K];
};
class MyService {
id: number = 1;
fetchData() {}
calculate() {}
}
type ServiceMethods = OnlyMethods<MyService>; // { fetchData: () => void; calculate: () => void; }
5. 条件类型(Conditional Types)
条件类型基于条件表达式选择不同的类型,语法为 T extends U ? X : Y:
// 基础条件类型
type IsString<T> = T extends string ? true : false;
type A = IsString<'hello'>; // true
type B = IsString<123>; // false
// 实用例子:从数组中提取元素类型
type Flatten<T> = T extends Array<infer U> ? U : T;
type Numbers = Flatten<number[]>; // number
type Mixed = Flatten<(string | number)[]>; // string | number
// 嵌套条件类型:检查元组类型
type IsTuple<T> =
T extends readonly any[] ?
number extends T['length'] ? false : true
: false;
type T1 = IsTuple<[number, string]>; // true
type T2 = IsTuple<number[]>; // false
6. 类型推断与 infer 关键字
infer 关键字在条件类型中用于从比较类型中提取类型:
// 提取函数返回类型
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
function getUser() {
return { name: 'Alice', age: 30 };
}
type User = ReturnType<typeof getUser>; // { name: string; age: number }
// 提取数组元素类型
type ArrayElement<T> = T extends (infer U)[] ? U : never;
type Colors = ArrayElement<string[]>; // string
// 提取 Promise 解析类型
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
type ResolvedValue = UnwrapPromise<Promise<number>>; // number
7. 模板文本类型(Template Literal Types)
模板文本类型允许基于字符串模板创建类型:
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
type ApiEndpoint = `/api/${string}`;
type ApiRoute = `${HttpMethod} ${ApiEndpoint}`;
function handleRequest(route: ApiRoute) {
// 处理路由
}
handleRequest('GET /api/users'); // 正确
handleRequest('POST /api/products'); // 正确
handleRequest('GET /users'); // 错误:不以/api开头
// 高级用法:路径参数提取
type ExtractParam<Path extends string> =
Path extends `${string}/:${infer Param}/${infer Rest}`
? [Param, ...ExtractParam<`/${Rest}`>]
: Path extends `${string}/:${infer Param}`
? [Param]
: [];
type Params = ExtractParam<'/users/:userId/posts/:postId'>;
// ['userId', 'postId']
8. 实用类型(Utility Types)
TypeScript 提供了一套内置的实用类型:
常用实用类型
// Partial:所有属性变为可选
type PartialUser = Partial<User>;
// Readonly:所有属性变为只读
type ReadonlyUser = Readonly<User>;
// Pick:选择特定属性
type UserName = Pick<User, 'name'>;
// Omit:排除特定属性
type UserWithoutEmail = Omit<User, 'email'>;
// Record:创建属性映射
type PageViews = Record<'home' | 'about' | 'contact', number>;
// Exclude:从联合类型中排除某些类型
type Letters = 'a' | 'b' | 'c';
type WithoutC = Exclude<Letters, 'c'>; // 'a' | 'b'
// Extract:从联合类型中提取可赋给特定类型的类型
type Numericals = Extract<string | number | boolean, number | string>; // string | number
自定义实用类型
// 深度只读
type DeepReadonly<T> = {
readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K];
};
// 深度可选
type DeepPartial<T> = {
[K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
};
// 不可为空类型
type NonNullableProperties<T> = {
[K in keyof T]: NonNullable<T[K]>;
};
// 函数参数类型
type ParametersExceptFirst<T> =
T extends (first: any, ...rest: infer U) => any ? U : never;
function greet(greeting: string, name: string, punctuation: string) {
return `${greeting}, ${name}${punctuation}`;
}
type GreetParams = ParametersExceptFirst<typeof greet>; // [string, string]
9. 递归类型(Recursive Types)
递归类型允许类型定义引用自身,非常适合定义树形结构:
// JSON 值类型(递归定义)
type JSONValue =
| string
| number
| boolean
| null
| JSONValue[]
| { [key: string]: JSONValue };
// 文件系统结构
type File = {
name: string;
size: number;
};
type Directory = {
name: string;
children: Array<File | Directory>;
};
type FileSystem = Directory;
// 链表结构
type ListNode<T> = {
value: T;
next: ListNode<T> | null;
};
const list: ListNode<number> = {
value: 1,
next: {
value: 2,
next: {
value: 3,
next: null
}
}
};
10. 声明合并(Declaration Merging)
声明合并允许将多个同名的接口声明合并为一个:
// 接口合并
interface User {
name: string;
}
interface User {
age: number;
}
const user: User = {
name: 'Alice',
age: 30
};
// 命名空间合并
namespace MathUtils {
export function add(a: number, b: number) {
return a + b;
}
}
namespace MathUtils {
export function subtract(a: number, b: number) {
return a - b;
}
}
console.log(MathUtils.add(5, 3)); // 8
console.log(MathUtils.subtract(5, 3)); // 2
实际应用场景
1. 实现类型安全的 Redux reducer
type Action<T extends string, P> = {
type: T;
payload: P;
};
function createAction<T extends string, P>(type: T, payload: P): Action<T, P> {
return { type, payload };
}
// 定义动作
const loginAction = createAction('USER_LOGIN', { username: 'alice', token: 'abc123' });
const logoutAction = createAction('USER_LOGOUT', undefined);
// 动作类型
type Actions = ReturnType<typeof loginAction> | ReturnType<typeof logoutAction>;
// Reducer
function userReducer(
state: UserState | null,
action: Actions
): UserState | null {
switch (action.type) {
case 'USER_LOGIN':
return action.payload; // 自动推断为登录载荷类型
case 'USER_LOGOUT':
return null;
default:
return state;
}
}
2. API 响应类型转换
// API 响应结构
type ApiResponse<T> = {
status: 'success' | 'error';
timestamp: string;
data: T;
error?: string;
};
// 用户API
type UserApiResponse = ApiResponse<{
id: number;
name: string;
email: string;
}>;
// 提取数据类型的实用类型
type ApiData<T> = T extends ApiResponse<infer D> ? D : never;
// 处理API响应
async function fetchData<T>(url: string): Promise<ApiData<T>> {
const response = await fetch(url);
const result: T = await response.json();
if (result.status === 'error') {
throw new Error(result.error || 'Unknown error');
}
return result.data; // 返回提取的数据部分
}
// 使用
const userData = await fetchData<UserApiResponse>('/api/user');
console.log(userData.name); // 类型安全访问
高级类型的最佳实践
-
渐进式类型化:
// 从简单类型开始,逐步增加复杂性 type PaymentMethod = 'credit_card' | 'paypal'; // 添加更多细节 type PaymentDetails = | { method: 'credit_card'; cardNumber: string; expiry: string } | { method: 'paypal'; email: string }; // 最终整合 type Payment = { amount: number; currency: string; } & PaymentDetails; -
优先使用类型别名:
// 更清晰地表达复杂类型关系 type Coordinates = [number, number]; type Address = { street: string; city: string; coords: Coordinates; }; -
利用类型推导减少冗余:
const config = { apiUrl: 'https://api.example.com', timeout: 5000, maxRetries: 3 } as const; // 使用const断言 type Config = typeof config; // 自动推导为:{ readonly apiUrl: "https://api.example.com"; readonly timeout: 5000; readonly maxRetries: 3; } -
组合而非继承:
// 使用组合而不是类继承 type Entity = { id: string; createdAt: Date; }; type User = Entity & { name: string; email: string; }; type Product = Entity & { name: string; price: number; };
常见错误和解决方案
错误1:过度复杂的类型
症状:类型定义嵌套过深,难以理解
解决方案:
// 分解复杂类型
type UserAuthentication = {
username: string;
passwordHash: string;
lastLogin: Date;
};
type UserProfile = {
displayName: string;
avatarUrl: string;
};
type User = UserAuthentication & UserProfile;
错误2:类型别名滥用
症状:为简单类型创建不必要的别名
解决方案:只在提高可读性或减少重复时使用类型别名
错误3:忽略性能影响
症状:复杂的递归类型导致类型检查缓慢
解决方案:
// 使用接口限制递归深度
type JsonValue =
| string
| number
| boolean
| null
| { [key: string]: JsonValue }
| JsonValue[];
TypeScript 高级类型的未来
随着 TypeScript 的持续发展,更多高级功能正在引入:
-
satisfies运算符(TypeScript 4.9+)const colors = ['red', 'green', 'blue'] satisfies string[]; const firstColor = colors[0]; // 正确推断为 string -
装饰器元数据(TypeScript 5.0+)
@Reflect.metadata('design:type', Function) class MyDecorator { // ... } -
扩展模式匹配能力
// 未来可能支持(提案阶段) type First<T> = T extends [infer First, ...infer _] ? First : never;
小结
TypeScript 的高级类型系统极大地增强了语言的表达能力,提供了以下优势:
- 类型安全:在编译时捕获更多错误
- 代码可维护性:明确的类型定义作为文档
- 开发效率:智能工具提示和自动完成
- 架构清晰度:表达复杂的数据结构和模式
graph TD
A[基础类型]
B[高级类型]
A -->|扩展为| B
B --> C[组合类型]
B --> D[条件类型]
B --> E[映射类型]
B --> F[实用类型]
B --> G[模板文本类型]
B --> H[递归类型]
C --> I[联合类型]
C --> J[交叉类型]
D --> K[类型推断]
D --> L[类型守卫]
E --> M[键映射]
E --> N[键过滤]
F --> O[内置实用类型]
F --> P[自定义类型工具]
通过掌握这些高级类型,你可以创建更具表现力的类型定义,构建更健壮的应用,并在团队协作中提供清晰的接口契约。TypeScript 的类型系统就像一张安全网,而高级类型使它更加坚固。