TypeScript 如何定义泛型
买奶茶时,你一定遇到过这种情况:店员问你“要什么甜度?”,不管你选全糖、半糖还是三分糖,奶茶的本质都是“你点的饮品”,不会变成咖啡或蛋糕。这种“统一规则下的灵活选择”,放到编程里,就是泛型的核心逻辑——让代码既能复用逻辑,又能适配不同类型的需求。
很多新手刚学TypeScript时,会觉得“泛型是很高级的东西”,其实它就像奶茶的甜度选项,是帮你避免重复写代码的工具。比如你要写一个“存数据的盒子”,如果不用泛型,就得分别写一个存数字的盒子、存字符串的盒子、存对象的盒子,每次换类型都要重写;用了泛型,你只要写一次规则,就能存任何类型的数据。

最基础的泛型:像奶茶杯的“定制选项”
先从最简单的例子说起,假设你要做一个“装东西的容器”,不管装的是硬币还是便签,容器的逻辑都是“放进去、拿出来”。不用泛型的话,你可能会写:
`typescript
// 存数字的盒子
function getBoxOfNumber(item: number): number {
return item;
}
// 存字符串的盒子
function getBoxOfString(item: string): string {
return item;
}
`
这时候你会发现,逻辑几乎一模一样,只是类型变了。用泛型改造后,就只需要写一次:
`typescript
// T就是“任意类型”的占位符,像奶茶的甜度选项
function getBox<T>(item: T): T {
return item;
}
// 用的时候只需要指定T是什么类型
const numberBox = getBox<number>(10); // 存数字的盒子
const stringBox = getBox<string>("奶茶"); // 存字符串的盒子
`
这里的T就像奶茶的“甜度选择”,你选number,它就按数字处理;选string,就按字符串处理,全程不用改核心逻辑。
泛型的“边界限制”:不是什么都能装
泛型虽然灵活,但不能乱选类型——就像奶茶杯不能装开水(会烫坏),泛型也得给类型设“边界”。比如你要做一个“能显示长度的盒子”,不是所有类型都有长度:数字没有长度,布尔值也没有,只有字符串、数组这类有长度的类型才可以。
这时候就要用“extends”给泛型设边界:
`typescript
// 只有有length属性的类型才能用这个泛型
function showLength<T extends { length: number }>(item: T): number {
return item.length;
}
// 正确用法:字符串有length
showLength("珍珠奶茶"); // 返回4
// 正确用法:数组有length
showLength([1,2,3]); // 返回3
// 错误用法:数字没有length,会报错
showLength(5); // 代码会提示你“数字不符合要求”
`
这个边界就像“奶茶杯的适用范围”,你不能拿杯子装开水,代码也不会让你用不符合要求的类型,避免出现奇怪的错误。
泛型在实际开发中的用处:解决重复麻烦
实际做项目时,泛型能帮你省很多事。比如你要做一个“从服务器拿数据的工具”,不管拿的是用户信息、商品列表还是订单记录,请求和解析的逻辑都是一样的。不用泛型的话,你得写好几个接口函数;用泛型的话,一个函数就能搞定:
`typescript
// 拿数据的函数,返回的类型由传入的泛型决定
async function fetchData<T>(url: string): Promise<T> {
const res = await fetch(url);
return res.json() as T;
}
// 拿用户信息,指定泛型为用户类型
interface User { name: string; age: number }
const user = await fetchData<User>("/api/user");
// 拿商品列表,指定泛型为商品类型
interface Product { id: number; name: string }
const products = await fetchData<Product[]>("/api/products");
`
这就像你有一个万能奶茶杯,不管是装奶茶、装柠檬水还是装冰美式,都不用换杯子,只要换里面的饮品就行。
泛型不是复杂的语法,而是帮你“一次写好规则,适配多种场景”的工具——就像奶茶的定制选项,既满足了不同人的需求,又不用重新做一个杯子。只要记住“泛型是类型的占位符,给它指定类型就会按对应规则处理”,再结合边界限制的规则,就能轻松用好它。