泛型接口和泛型类的核心作用是把类型“留空”,使用时再填入具体类型,兼顾类型安全与复用性;声明时在接口或类名后加<T>,使用时指定具体类型如Config<string>或Stack<number>,支持多参数如Pair<K, V>,可自动推导,静态成员不可用T,仅编译期有效。

泛型接口和泛型类的核心作用是把类型“留空”,等到使用时再填入具体类型,既保持类型安全,又避免重复写多个相似结构。
泛型接口的声明与使用
泛型接口在定义时把类型参数写在接口名后面,调用时再指定具体类型。
- 声明方式:接口名后加 <T>,方法或属性中用 T 代表该类型
- 例如:interface Config<T> { (value: T): T } —— 表示这个函数接受并返回同一种类型
- 使用时可显式传入类型:const fn: Config<string> = (x) => x
- 也可让 TypeScript 自动推导:const fn = <T>(x: T) => x; fn('hello');(此时不用写 Config<string>)
- 支持多个泛型参数:interface Pair<K, V> { key: K; value: V; },使用时写 Pair<string, number>
泛型类的声明与实例化
泛型类把类型参数放在类名后,实例化时决定具体类型,类内部所有用到该泛型的地方都会被统一约束。
- 声明方式:class Stack<T> { items: T[] = []; push(item: T): void { this.items.push(item); } }
- 实例化时传入类型:const stack = new Stack<number>(); —— 此时 push 只接受 number
- 也可以省略显式类型,靠构造参数推断:const stack = new Stack(); stack.push(123); → 推出 T 是 number
- 注意:泛型只作用于实例成员,静态方法/属性不能直接使用泛型参数 T
泛型接口和泛型类配合使用的常见场景
比如定义一个通用的数据处理器,接口描述行为,类实现逻辑。
- 先定义泛型接口:interface Processor<T> { process(input: T): T; }
- 再用泛型类实现:class StringProcessor implements Processor<string> { process(s: string): string { return s.toUpperCase(); } }
- 或者更灵活地让类也泛型化:class GenericProcessor<T> implements Processor<T> { ... },实例化时再定类型
不复杂但容易忽略:泛型不是运行时特性,它只在编译期起作用;传入的类型必须是合法类型,比如 <any> 或 <unknown> 可以,但 <'abc'> 这种字面量类型也完全合法,只是需确保上下文能匹配。


















