多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[TOC] >[success] # 泛型(Generics) 第一部分 ![](https://img.kancloud.cn/08/cb/08cb56d19fc956d2ce623b65258b4068_359x297.png) 上面用一张图描述了学习 **TypeScript** 的一个过程, **Adding simple type annotations** 的意思是 **给我们的变量加一些简单的类型声明** ,这个 **滑梯很平滑** ,但是到了 **Generics(泛型)** 就直线下降到 **地狱难度** ,这意味着,我们只要掌握了 **Generics(泛型)** 就把 **typescript** 给攻破了,接下来我们讲一讲 **Generics(泛型)** 是怎么出现的,它是 **为了解决什么问题** ? >[success] ## 函数使场景问题 demo 举例:现在我们有一个 **函数 echo** ,它只做一件事,我们 **传入一个参数,它把参数返回** **index.ts** ~~~ function echo (arg){ return arg } const result = echo(123) ~~~ **编辑器图片** : ![](https://img.kancloud.cn/e0/0d/e00d3580515c61c36a1e23ed3ced52e5_286x137.png) 上面的代码会出现什么问题呢 ?我们 **传入的数字 123** ,鼠标指向 **result** 时,返回的类型是 **any** ,这 **不是我们想要的结果,这样我们的变量就丧失了类型** ,这不是一个好现象,怎么办呢,我们 **给函数的参数以及返回的参数定义一个 number 类型** ,代码如下: **index.ts** ~~~ function echo (arg: number): number{ return arg } const result = echo(123) ~~~ **编辑器图片**: ![](https://img.kancloud.cn/0f/67/0f67c50bcb1a05812dab8941a6ee7dd6_377x130.png) 但是我们有可能想 **不单单只是想传入 number 类型的参数,有可能是 string、boolean 甚至是复杂类型** ,该怎么办呢,大家可能就会想了,换成 **any** 呗,代码如下: **index.ts** ~~~ function echo (arg: any): any{ return arg } const result = echo(123) ~~~ 但是这还不是我们想要的结果,这只能说 **传入的值是 any ,返回的值也是 any** ,但是我们 **传入与返回的值都无法做到统一** ,我们还是 **丧失了类型** ,甚至我们还可以出现一个 **bug** ,还可以把 **result** 常量 **定义成 string** 类型,因为 **echo 返回的是 any 类型,string 属于 any 下的一个类型** ,代码如下: **index.ts** ~~~ function echo (arg: any): any{ return arg } const result:string = echo(123) ~~~ **编辑器图片**: ![](https://img.kancloud.cn/02/5b/025b320cc50b5207c94e0fda7cbf4af0_356x134.png) 但是理论上我们都知道,我们 **传入的 数字,要返回一个 number** ,那么怎么样来解决这个问题呢,这时候 **泛型(Generics)** 就来拯救我们了。 >[success] ## 用泛型(Generics)解决函数问题 **泛型(Generics)** : 在 **定义函数、接口、Class类时,我们不预先指定具体类型,而是在使用时再指定类型** 我们要写 **泛型(Generics)** 首先要找到 **函数名称 echo** , 在 **echo 后面加一对尖括号(<T\>),尖括号里面可以定义泛型(Generics)的名称** ,我这里就叫做 **T** ,这个 **名称叫什么都可以**, **T** 只是一种习惯的写法罢了,这样 **我们就创造了我们第一个泛型的参数** ,相当于 **它创造了一个占位符 ,这个占位符叫 T** ,可以 **把它看做是一个神秘的变量** ,它现在是什么 **类型** 我们不知道,可以是 **任意类型**,在使用时候我会讲到,这时候我们把 **参数的类型** 改成 **T** , **返回值** 也 **修改成 T** ,具体代码如下: **index.ts** ~~~ function echo<T>(arg: T): T{ return arg } const str: string = 'str' const result = echo(str) ~~~ **编辑器图片**: ![](https://img.kancloud.cn/52/18/5218b1d505123d0d648977f9342f7e53_363x217.png) 传入的是 **string** , **返回** 的也是 **string** ,这样就达到了我们想要的效果,当然我们也可以不给 **str 常量定义类型**,因为它可以自动做 **[类型推论](https://www.kancloud.cn/wangjiachong/vue_notes/2165550)** ,代码如下: **index.ts** ~~~ function echo<T>(arg: T): T{ return arg } const result = echo('str') ~~~ **编辑器图片**: ![](https://img.kancloud.cn/2a/d2/2ad28d3da6c467cb83490043e688c43c_303x127.png) 当然刚才上面说的那个 **bug** 也不会再出现了,如下: **index.ts** ~~~ function echo<T>(arg: T): T{ return arg } const result:string = echo(123) ~~~ **编辑器图片**: ![](https://img.kancloud.cn/b0/27/b0275242ed7c8494c96e9bf905143e23_544x192.png) >[success] ## 泛型(Generics)传多个值 **需求**: 我们有一个 **[元祖](https://www.kancloud.cn/wangjiachong/vue_notes/2165547#_26)** ,里面有 **2 个值** , **它们的类型都是随意的** ,这时候我们要 **返回一个新的元祖** **index.ts** ~~~ function swap(tuple){ return [tuple[1], tuple[0]] } ~~~ 像上面这样写,我们就会 **丧失它们的类型** ,我们需要这样写: **index.ts** ~~~ function swap<T, U>(tuple: [T, U]):[U, T] { return [tuple[1], tuple[0]] // 注意返回的类型是 [U,T], 不是 [T, U] } const result = swap(['string', 123]) ~~~ **编辑器图片**: ![](https://img.kancloud.cn/73/c7/73c7f64058e7dcf5cf0aab0444f8dbcb_700x157.png) 这样的话 **result** 的第 **0** 个就是 **number 类型** ,第 **1** 个就是 **string 类型** ,我们可以使用 **对应类型给提供的方法** ,如下图: ![](https://img.kancloud.cn/13/d0/13d01119dcd41d41fc4fab756aea9c71_809x472.png)