泛型是解决“写一遍逻辑、适配多种类型”问题的实用工具,核心在于减少重复、降低错误、提前暴露问题;应从具体痛点出发,通过三步练习(删any、加约束、拆静态方法)和真实场景小练习掌握。

泛型不是语法炫技,而是解决“写一遍逻辑、适配多种类型”这个实际问题的工具。关键不在背规则,而在理解它怎么帮你少出错、少复制、早发现问题。
从一个具体痛点开始写
别一上来就定义 class Container<t></t>。先想你正在写的代码里哪块重复了:
- 比如你写了三个方法:一个取
User[]的第一个元素,一个取Product[]的第一个,一个取Order[]的第一个——逻辑完全一样,只改了类型 - 又比如你封装了一个缓存类,现在只能存
string,但下周要加图片数据、配置数据,类型各不相同
这时候就把重复部分抽出来,把“类型”变成参数。例如 TypeScript 中直接写:
function getFirst调用时不用改函数,只换入参类型:getFirst(users) 返回 User,getFirst(products) 返回 Product。
动手练习三步走
练习不是看懂,是亲手写出能跑、能报错、能改错的代码:
-
第一步:删掉 any —— 找一个你项目里用
any[]或Object当容器的地方,改成<t></t>,让编辑器立刻标出所有漏转型的地方 -
第二步:加约束 —— 比如你写了个排序函数,发现需要调用
.compareTo(),那就加<t extends comparable>></t>(Java)或<t extends id: number></t>(TS),试试不满足条件的类型传进去会怎样 -
第三步:拆静态方法 —— 在泛型类里写个静态工厂方法,比如
createEmpty(): T[],你会发现编译失败——这时你就得改成static <u> U[] createEmpty()</u>,真正理解“静态方法的泛型和类泛型无关”
避开高频翻车点
这些不是细节,是写泛型时最常卡住的地方:
-
泛型不能用于字段声明 —— 类里不能写
private T cache;,因为 T 是实例创建时才确定的,而字段在类加载时就得分配内存 -
ArrayList
不是 ArrayList —— 它们是完全不同的类型,就像“苹果箱”不是“水果箱”的子类,往里塞香蕉会出事 -
基本类型不能直接当泛型实参 —— Java 里
ArrayList<int></int>是错的,必须用Integer;C# 里List<int></int>可以,但底层做了装箱处理
真实场景小练习
选一个马上能用上的例子,花 15 分钟实现:
- 一个通用的请求封装函数:
request<t>(url: string): Promise<t></t></t>,返回的数据自动是你要的类型 - 一个带类型的事件总线:
EventBus<events></events>,其中Events是个联合类型如'login' | 'logout',发布和监听时类型自动对齐 - 一个可配置的验证器:
Validator<t> = (value: unknown) => value is T</t>,校验后直接获得类型收窄
写完运行,故意传错类型看看报错位置,再改对。比读十页文档管用。











