TypeScript高级技巧:泛型与类型体操
·
TypeScript高级技巧:泛型与类型体操
大家好,我是欧阳瑞(Rich Own)。今天想和大家聊聊TypeScript的高级特性,特别是泛型和类型体操。作为一个全栈开发者,我发现TypeScript的类型系统非常强大,掌握好这些技巧可以大大提高代码的健壮性和可维护性。
什么是泛型?
泛型是TypeScript中一种强大的工具,允许我们编写可重用的组件,同时保持类型安全。
基础泛型
泛型函数
function identity<T>(arg: T): T {
return arg;
}
// 使用
const num = identity<number>(42);
const str = identity<string>("hello");
泛型接口
interface Container<T> {
value: T;
getValue: () => T;
}
const numberContainer: Container<number> = {
value: 42,
getValue: () => 42
};
泛型类
class Box<T> {
private items: T[] = [];
add(item: T): void {
this.items.push(item);
}
get(index: number): T {
return this.items[index];
}
}
泛型约束
使用接口约束
interface Lengthwise {
length: number;
}
function logLength<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}
logLength("hello"); // 5
logLength([1, 2, 3]); // 3
logLength({ length: 10, value: "test" }); // 10
类型参数约束
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const person = { name: "Alice", age: 30 };
const name = getProperty(person, "name"); // string
const age = getProperty(person, "age"); // number
条件类型
基础条件类型
type IsString<T> = T extends string ? true : false;
type A = IsString<string>; // true
type B = IsString<number>; // false
分布式条件类型
type Flatten<T> = T extends Array<infer U> ? U : T;
type Flattened = Flatten<number[]>; // number
type NotFlattened = Flatten<string>; // string
infer关键字
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type Func = () => string;
type Result = ReturnType<Func>; // string
类型体操实战
1. 实现Pick
type MyPick<T, K extends keyof T> = {
[P in K]: T[P];
};
interface User {
id: number;
name: string;
age: number;
}
type UserName = MyPick<User, "name">; // { name: string }
2. 实现Readonly
type MyReadonly<T> = {
readonly [P in keyof T]: T[P];
};
interface Config {
apiUrl: string;
timeout: number;
}
type ReadonlyConfig = MyReadonly<Config>;
3. 实现TupleToObject
type TupleToObject<T extends readonly any[]> = {
[P in T[number]]: P;
};
const tuple = ["a", "b", "c"] as const;
type ObjectType = TupleToObject<typeof tuple>; // { a: "a", b: "b", c: "c" }
4. 实现First
type First<T extends any[]> = T extends [infer U, ...any[]] ? U : never;
type A = First<[1, 2, 3]>; // 1
type B = First<[]>; // never
5. 实现Length
type Length<T extends readonly any[]> = T["length"];
type A = Length<[1, 2, 3]>; // 3
type B = Length<[]>; // 0
映射类型
基础映射类型
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];
};
type Mutable<T> = {
-readonly [P in keyof T]: T[P];
};
条件映射类型
type Nullable<T> = {
[P in keyof T]: T[P] | null;
};
type NullableUser = Nullable<User>; // { id: number | null; name: string | null; age: number | null }
模板字面量类型
基础模板字面量
type Color = "red" | "green" | "blue";
type Size = "small" | "medium" | "large";
type ColorSize = `${Color}-${Size}`; // "red-small" | "red-medium" | "red-large" | ...
转换类型
type Uppercase<T extends string> = `${Uppercase<T>}`;
type Lowercase<T extends string> = `${Lowercase<T>}`;
type Capitalize<T extends string> = `${Capitalize<T>}`;
type Uncapitalize<T extends string> = `${Uncapitalize<T>}`;
type A = Uppercase<"hello">; // "HELLO"
type B = Capitalize<"hello">; // "Hello"
递归类型
深度Readonly
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object
? DeepReadonly<T[P]>
: T[P];
};
interface NestedObject {
a: {
b: {
c: number;
};
};
}
type ReadonlyNested = DeepReadonly<NestedObject>;
深度Partial
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object
? DeepPartial<T[P]>
: T[P];
};
工具类型实战
实现Promise类型提取
type UnwrapPromise<T> = T extends Promise<infer U> ? UnwrapPromise<U> : T;
type A = UnwrapPromise<Promise<string>>; // string
type B = UnwrapPromise<Promise<Promise<number>>>; // number
实现函数重载类型
type OverloadUnion<T> = T extends { (...args: infer A): infer R } ? (...args: A) => R : never;
type Fn = {
(a: string): number;
(a: number): string;
};
type Result = OverloadUnion<Fn>; // ((a: string) => number) | ((a: number) => string)
实际应用场景
1. 类型安全的状态管理
type Action<T> = {
type: string;
payload: T;
};
type Reducer<S, A> = (state: S, action: A) => S;
function createStore<S, A extends Action<any>>(
reducer: Reducer<S, A>,
initialState: S
) {
let state = initialState;
return {
getState: () => state,
dispatch: (action: A) => {
state = reducer(state, action);
}
};
}
2. 类型安全的API调用
type ApiResponse<T> = {
data: T;
status: number;
message: string;
};
async function fetchApi<T>(url: string): Promise<ApiResponse<T>> {
const response = await fetch(url);
return response.json();
}
interface User {
id: number;
name: string;
}
const userResponse = await fetchApi<User>("/api/user");
const user: User = userResponse.data;
3. 类型安全的事件系统
type EventMap = {
"user:created": { userId: number; name: string };
"user:updated": { userId: number; changes: Partial<User> };
"system:error": { message: string; code: number };
};
class EventEmitter {
private listeners: {
[K in keyof EventMap]?: ((event: EventMap[K]) => void)[];
} = {};
on<K extends keyof EventMap>(event: K, listener: (event: EventMap[K]) => void) {
if (!this.listeners[event]) {
this.listeners[event] = [];
}
this.listeners[event]!.push(listener);
}
emit<K extends keyof EventMap>(event: K, data: EventMap[K]) {
this.listeners[event]?.forEach(listener => listener(data));
}
}
总结
TypeScript的类型系统非常强大,掌握泛型和类型体操可以让你写出更加健壮和可维护的代码。从简单的泛型函数到复杂的类型体操,每一步都在提升代码的类型安全。
我的鬃狮蜥Hash对TypeScript也有自己的理解——它总是根据不同的蟋蟀类型选择不同的捕食策略,这也许就是自然界的"类型推断"吧!
如果你有TypeScript方面的问题,欢迎留言交流!我是欧阳瑞,极客之路,永无止境!
技术栈:TypeScript · 泛型 · 类型体操
更多推荐


所有评论(0)