TypeScript 泛型函数

在上一节中,我们用一个简单的回声函数(echo)初步体验了泛型的魅力。实际上,像那种在定义时带有 “<T>” 的函数,就是 “泛型函数”。

在真实的项目开发中,泛型函数经常用于处理复杂的数据结构(如数组、对象、元组等)。咱们在这一节中,将带领小伙伴们学习一下泛型函数在真实业务中的玩法。

TypeScript 泛型函数与数组

在实际开发中,我们经常需要编写一些工具函数来处理数组。假设我们需要一个函数:根据传入的长度和初始值,自动生成一个数组

如果不使用泛型,我们可能会用 any 来兜底,但这会导致生成的数组丢失所有类型提示。此时,泛型函数就派上大用场了。

示例 1:创建一个通用的数组生成函数

// 定义泛型函数,T 代表初始值的类型
function createArray<T>(length: number, value: T): T[] {
    let result: T[] = [];
    for (let i = 0; i < length; i++) {
        result.push(value);
    }
    return result;
}

// 传入数字
const numArr = createArray(3, 2026);
console.log(numArr);

// 传入字符串
const strArr = createArray(3, "绿叶网");
console.log(strArr);

运行结果如下。

[ 2026, 2026, 2026 ]
[ '绿叶网', '绿叶网', '绿叶网' ]

分析:

我们在函数名 createArray() 后面加上 “<T>” 来声明了一个泛型变量,然后参数 value 的类型被指定为 “T”。最巧妙的地方是,返回值类型被指定为 “T[]”(T类型的数组)。

当我们传入 "绿叶网" 时,TypeScript 会自动推断 “T” 是 string,进而推断出 strArr 的类型是 string[]。后续如果我们对 strArr 使用数组方法,则编辑器会提供完美的智能提示。

TypeScript 函数的多泛型参数(<T, U>)

有时候,一个函数需要处理多个不同类型的参数。既然泛型是变量,那我们当然可以声明多个泛型变量。

一般情况下,我们会按照字母表的顺序,继续使用 U、V 等字母来代表第 2个、第 3 个泛型变量。

示例 2:多泛型参数实现 “元组交换”

// 声明 2 个泛型变量:T 和 U
function swap<T, U>(tuple: [T, U]): [U, T] {
    return [tuple[1], tuple[0]];
}

// 传入 [数字, 字符串]
const swappedResult = swap([2026, "绿叶网"]);

console.log(swappedResult[0]);
console.log(swappedResult[1]);

运行结果如下。

绿叶网
2026

分析:

在这个例子中,我们定义了一个函数 swap(),用于接收一个包含两个元素的元组,然后把它们的位置调换一下再返回。

当我们给 swap() 函数传入 [2026, "绿叶网"] 作为参数时,TypeScript 会自动推断第 1 个参数类型是 number,第 2 个参数是 string。然后将 “T” 绑定为了 string,将 “U” 绑定为了 number。

由于函数返回值类型写的是 [U, T],因此 TypeScript 也能知道返回的结果必然是 [string, number] 类型。

TypeScript 箭头函数中的泛型

在现代前端开发(如 Vue 3 的 Composition API)中,我们会大量使用箭头函数。在箭头函数中使用泛型,语法稍有不同,我们需要将 “<T>” 放在括号的前面。

示例 3:箭头函数泛型写法

// 箭头函数定义泛型变量
const echo = <T>(arg: T): T => {
    return arg;
};

const result = echo("绿叶网");
console.log(result);

运行结果如下。

绿叶网

分析:

需要注意的是,如果你是在 “Vue 的 .tsx 文件” 或者 “React 的 .jsx 文件” 中编写上面的箭头函数,此时编辑器大概率会亮起红色的波浪线报错。

这是因为在 TSX/JSX 语法中,编译器看到 <T> 时,会误以为这是一个 HTML 标签(类似于 <div>),从而导致解析失败。

为了明确告诉编译器 “这是一个泛型、不是 HTML 标签”,业界有一个非常经典的 Hack 写法——在泛型字母后面加一个英文逗号(,)。

// 强烈推荐:在泛型后加逗号,完美兼容 TSX 语法
const safeEcho = <T,>(arg: T): T => {
    return arg;
};

上一篇: TypeScript 泛型

下一篇: TypeScript 泛型接口

给站长反馈

绿叶网正在不断完善中,小伙伴们如果发现任何问题,还望多多给站长反馈,谢谢!

邮箱:lvyenet@vip.qq.com

「绿叶网」服务号
绿叶网服务号放大
关注服务号,微信也能看教程。
绿叶网服务号