前端工程Technical Deep Dive
TypeScript 高级类型 —— 泛型、条件类型、映射类型完全指南
发布时间2026/03/29
分类前端工程
预计阅读2 分钟
作者吴长龙
*
TypeScript 类型系统概述
01.内容
TypeScript 类型系统概述
TypeScript 的类型系统是其核心优势,从基础类型到高级类型,形成了一套强大的类型编程能力。
一、泛型(Generics)
#### 基本泛型
typescript snippettypescript
// 泛型函数
function identity<T>(arg: T): T {
return arg;
}
const str = identity('hello'); // type: string
const num = identity(123); // type: number
// 泛型接口
interface Container<T> {
value: T;
getValue(): T;
}
const container: Container<string> = {
value: 'hello',
getValue() { return this.value; }
};#### 泛型约束
typescript snippettypescript
// 约束为特定类型
interface Lengthwise {
length: number;
}
function logLength<T extends Lengthwise>(arg: T): void {
console.log(arg.length);
}
logLength('hello'); // OK
logLength([1, 2, 3]); // OK
logLength({ length: 5 }); // OK
// logLength(123); // Error
// 约束为另一个类型参数
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const obj = { a: 1, b: 'hello' };
getProperty(obj, 'a'); // type: number
getProperty(obj, 'b'); // type: string
// getProperty(obj, 'c'); // Error#### 泛型类
typescript snippettypescript
class Stack<T> {
private items: T[] = [];
push(item: T): void {
this.items.push(item);
}
pop(): T | undefined {
return this.items.pop();
}
}
const numberStack = new Stack<number>();
numberStack.push(1);
numberStack.push(2);
const num = numberStack.pop(); // type: number | undefined二、条件类型
#### 基础条件类型
typescript snippettypescript
type IsString<T> = T extends string ? true : false;
type A = IsString<string>; // true
type B = IsString<number>; // false
// 提取元素类型
type ArrayElement<T> = T extends (infer U)[] ? U : never;
type Elem = ArrayElement<string[]>; // string
type Elem2 = ArrayElement<number[]>; // number#### 高级用法:分布式条件类型
typescript snippettypescript
type ToArray<T> = T extends any ? T[] : never;
type StrOrNumArr = ToArray<string | number>;
// 等价于: string[] | number[]
// 实际应用:排除 null/undefined
type NonNullable<T> = T extends null | undefined ? never : T;
type A = NonNullable<string | null | undefined>; // string#### 预定义条件类型
typescript snippettypescript
// Extract: 提取可赋值的类型
type Extract<T, U> = T extends U ? T : never;
type T = Extract<string | number, string>; // string
// Exclude: 排除可赋值的类型
type Exclude<T, U> = T extends U ? never : T;
type T2 = Exclude<string | number, string>; // number
// ReturnType: 获取函数返回类型
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
function getData() { return { id: 1 }; }
type Data = ReturnType<typeof getData>; // { id: number }
// Parameters: 获取函数参数类型
type Parameters<T> = T extends (...args: infer P) => any ? P : never;
function handleClick(id: string, name: string) {}
type Params = Parameters<typeof handleClick>; // [string, string]三、映射类型
#### 基础映射
typescript snippettypescript
type Props = {
id: number;
name: string;
email: string;
};
// 将所有属性转为可选
type Partial<T> = {
[P in keyof T]?: T[P];
};
type PartialProps = Partial<Props>;
// { id?: number; name?: string; email?: string; }
// 将所有属性转为只读
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
type ReadonlyProps = Readonly<Props>;
// { readonly id: number; readonly name: string; ... }#### 泛型映射
typescript snippettypescript
// pick: 选择部分属性
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
type Picked = Pick<Props, 'id' | 'name'>;
// { id: number; name: string; }
// omit: 排除部分属性
type Omit<T, K extends keyof T> = {
[P in Exclude<keyof T, K>]: T[P];
};
type Omitted = Omit<Props, 'email'>;
// { id: number; name: string; }四、模板字面量类型
typescript snippettypescript
// 基础用法
type EventName = `on${string}`;
type Handler = `handle${string}`;
const e: EventName = 'onClick'; // OK
const h: Handler = 'handleSubmit'; // OK
// 提取部分
type Color = 'red' | 'green' | 'blue';
type ColorProp = `color-${Color}`;
// "color-red" | "color-green" | "color-blue"
// 推断
type Route = '/users' | '/posts' | '/comments';
type ExtractRouteParams<T> = T extends `${string}:${infer P}/${infer Rest}`
? P | ExtractRouteParams<`/${Rest}`>
: T extends `${string}:${infer P}`
? P
: never;
// 实际应用
type UserRoute = '/users/:id/posts/:postId';
type Params = ExtractRouteParams<UserRoute>;
// "id" | "postId"五、实战:类型工具库
#### 1. 深 Partial
typescript snippettypescript
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};
type Nested = {
user: {
profile: {
name: string;
age: number;
};
};
};
type DeepNested = DeepPartial<Nested>;
// { user?: { profile?: { name?: string; age?: number; } } }#### 2. 严格类型
typescript snippettypescript
type StrictOmit<T, K extends keyof T> = {
[P in Exclude<keyof T, K>]: T[P];
};
type StrictPick<T, K extends keyof T> = {
[P in K]: T[P];
};
// 与内置的区别:严格模式下会报错#### 3. 函数类型增强
typescript snippettypescript
// 异步函数返回类型
type AsyncReturnType<T extends (...args: any) => Promise<any>> =
T extends (...args: any) => Promise<infer R> ? R : any;
// 组合函数
type Compose<T> = (arg: any) => T;
function pipe<T>(...fns: Array<(arg: any) => any>) {
return (input: any) => fns.reduce((acc, fn) => fn(acc), input);
}
// 用法
const process = pipe(
(x: number) => x + 1,
(x: number) => x * 2,
(x: number) => String(x)
);
// process: (input: number) => string六、类型守卫
typescript snippettypescript
// typeof 守卫
function padLeft(value: string | number, padding: string | number) {
if (typeof padding === 'number') {
return Array(padding + 1).join(' ') + value;
}
if (typeof padding === 'string') {
return padding + value;
}
throw new Error('Expected string or number');
}
// in 守卫
interface Fish { swim(): void; }
interface Bird { fly(): void; }
function move(animal: Fish | Bird) {
if ('swim' in animal) {
return animal.swim();
}
return animal.fly();
}
// 类型断言函数
function isString(value: any): value is string {
return typeof value === 'string';
}
function example(x: string | number) {
if (isString(x)) {
return x.toUpperCase(); // type: string
}
return x.toFixed(2); // type: number
}七、实战案例
#### 1. API 响应类型
typescript snippettypescript
type ApiResponse<T> =
| { success: true; data: T }
| { success: false; error: string };
async function fetchUser(id: string): Promise<ApiResponse<User>> {
try {
const user = await getUser(id);
return { success: true, data: user };
} catch (e) {
return { success: false, error: e.message };
}
}
// 使用时自动推断
const result = await fetchUser('1');
if (result.success) {
console.log(result.data.name); // User 类型
} else {
console.error(result.error); // string 类型
}#### 2. 事件处理类型
typescript snippettypescript
type EventMap = {
click: { x: number; y: number };
focus: { target: HTMLElement };
input: { value: string };
};
type EventCallback<T> = (data: T) => void;
class EventEmitter<T extends Record<string, any>> {
private listeners: {
[K in keyof T]?: Array<EventCallback<T[K]>>;
} = {};
on<K extends keyof T>(event: K, callback: EventCallback<T[K]>): void {
this.listeners[event] = (this.listeners[event] || []).concat(callback);
}
emit<K extends keyof T>(event: K, data: T[K]): void {
this.listeners[event]?.forEach(cb => cb(data));
}
}
const emitter = new EventEmitter<EventMap>();
emitter.on('click', (data) => {
console.log(data.x, data.y); // 类型安全
});
emitter.emit('click', { x: 10, y: 20 });总结
TypeScript 高级类型是构建类型安全应用的基础:
| 技术 | 用途 |
|---|---|
| 泛型 | 代码复用、类型参数化 |
| 条件类型 | 类型推导、类型过滤 |
| 映射类型 | 类型转换、属性修改 |
| 模板字面量 | 字符串类型构造 |
| 类型守卫 | 运行时类型检查 |
熟练掌握这些技术,能写出更安全、更可维护的代码。