摘要: 本文将介绍 TypeScript 中极具魔力的特性——泛型(Generics)。文章从一个简单的问题(如何在保持类型信息的同时创建可复用函数)入手,循序渐进地讲解了泛型函数、泛型接口和泛型约束的语法与应用场景。通过学习本篇,读者将能编写出高度灵活、可复用且类型安全的代码组件,真正发挥
TypeScript 的强大威力。
关键词: TypeScript 泛型, TypeScript Generics, 泛型函数, 泛型接口, 泛型约束, T, 代码复用, 类型抽象
在上一篇文章中,我们学会了使用 interface
和 type
来为各种数据结构建立精确的“蓝图”。现在,我们可以自信地定义一个 User
对象或一个 Product
对象。
但新的挑战随之而来:如果我们想编写一个通用的函数,它既能服务于 User
数组,也能服务于 Product
数组,同时还能保持各自严格的类型信息,该怎么做?
这就是今天要探讨的主题——泛型(Generics)。它是 TypeScript 中实现代码复用与类型安全完美结合的核心工具。
1. 问题的提出:一个“健忘”的函数
假设我们需要一个函数,它的功能很简单:接收一个数组,并返回该数组的第一项。
第一版尝试:使用 any
一个不了解泛型的开发者可能会这样写:
function getFirstElement(arr: any[]): any {
return arr[0];
}
const names = ["Alice", "Bob", "Eve"];
const firstNumber = getFirstElement([1, 2, 3]); // -> 1
const firstString = getFirstElement(names); // -> "Alice"
// 问题来了:
firstNumber.toFixed(2); // 在编码时,这里没有任何错误提示!
// 但 firstNumber 是数字,这行代码在运行时是OK的。
firstString.toFixed(2); // 编码时也OK,但运行时会报错,因为字符串没有 toFixed 方法!
any
方案虽然实现了函数的复用,但完全牺牲了类型安全。TypeScript 对 firstNumber
和 firstString
的类型一无所知,这让我们又回到了纯 JavaScript 的“危险”境地。
2. 泛型的魔力:类型变量 <T>
泛型使用一个类型变量(通常用 <T>
表示)来作为类型的“占位符”。当函数被调用时,TypeScript 会根据传入的参数自动推断出这个占位符应该代表的具体类型。
让我们用泛型重写上面的函数:
function getFirstElement