本文最后更新于 43 天前,其中的信息可能已经有所发展或是发生改变。
“泛型是TypeScript的类型体操,让静态类型拥有了动态表达能力” —— TypeScript核心贡献者
1️⃣ 泛型基础
1.1 泛型函数
// 基础泛型函数
function identity<T>(arg: T): T {
return arg;
}
// 自动类型推断
const output = identity("hello"); // 类型推断为string
// 显式指定类型
const num = identity<number>(100); // 明确指定number类型
1.2 泛型接口
interface GenericArray<T> {
[index: number]: T;
length: number;
}
const numberArray: GenericArray<number> = [1, 2, 3];
const stringArray: GenericArray<string> = ['a', 'b', 'c'];
1.3 泛型类
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
const myNumber = new GenericNumber<number>();
myNumber.zeroValue = 0;
myNumber.add = (x, y) => x + y;
const myString = new GenericNumber<string>();
myString.zeroValue = "";
myString.add = (a, b) => a.concat(b);
2️⃣ 类型操作符
2.1 泛型约束
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // 现在可以安全访问length属性
return arg;
}
2.2 条件类型
type NonNullable<T> = T extends null | undefined ? never : T;
type T0 = NonNullable<string | number | null>; // string | number
type T1 = NonNullable<string[] | null | undefined>; // string[]
2.3 映射类型
type Partial<T> = {
[P in keyof T]?: T[P];
};
interface Person {
name: string;
age: number;
}
type PartialPerson = Partial<Person>;
/* 等效于:
{
name?: string;
age?: number;
}
*/
3️⃣ 工程化实践
3.1 React组件Props泛型
interface ListProps<T> {
items: T[];
renderItem: (item: T) => React.ReactNode;
}
function GenericList<T>({ items, renderItem }: ListProps<T>) {
return (
<div>
{items.map((item, index) => (
<div key={index}>{renderItem(item)}</div>
))}
</div>
);
}
// 使用示例
<GenericList
items={[{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]}
renderItem={(user) => <span>{user.name}</span>}
/>
3.2 API响应类型封装
interface ApiResponse<T = any> {
code: number;
data: T;
message?: string;
}
type User = {
id: string;
name: string;
email: string;
};
const fetchUsers = async (): Promise<ApiResponse<User[]>> => {
const response = await fetch('/api/users');
return response.json();
};
4️⃣ 高级模式
4.1 泛型递归
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object
? DeepReadonly<T[P]>
: T[P];
};
interface NestedObject {
a: number;
b: {
c: boolean;
d: {
e: string;
};
};
}
type ReadonlyNested = DeepReadonly<NestedObject>;
4.2 类型推断
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
function getString() {
return "hello";
}
type T1 = ReturnType<typeof getString>; // string
5️⃣ 性能优化
5.1 类型实例化深度限制
// 避免超过默认的50层嵌套限制
type Tuple<T, N extends number> = N extends N
? number extends N
? T[]
: _Tuple<T, N, []>
: never;
type _Tuple<T, N extends number, R extends unknown[]> =
R['length'] extends N ? R : _Tuple<T, N, [T, ...R]>;
5.2 类型缓存策略
interface Cache<T = any> {
data: T;
timestamp: number;
}
const createCache = <T>(initialData: T): Cache<T> => ({
data: initialData,
timestamp: Date.now()
});
// 使用示例
const numberCache = createCache<number>(42);
const userCache = createCache({ name: 'Alice' }); // 自动推断类型
最佳实践:
- 优先使用类型推断而不是显式注解
- 避免过度复杂的嵌套泛型
- 合理使用泛型约束保证类型安全
- 对公共API进行完整的泛型文档说明
- 定期进行类型性能分析
常见错误:
// 错误:不必要的泛型参数
function badExample<T>(arg: any): any { /*...*/ }
// 正确:明确泛型的使用场景
function goodExample<T>(arg: T): T { /*...*/ }
扩展资源:
欢迎在评论区分享你的泛型使用心得! 🚀