TS入门之细说泛型generic

349 阅读4分钟

「这是我参与2022首次更文挑战的第18天,活动详情查看:2022首次更文挑战」。

软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。泛型是 TypeScript 中非常重要的一个概念,它可以给予开发者创造灵活、可重用代码的能力。

基本使用

有这样一个函数,参数接收一个string型的参数,返回同样需要是string型,可以这样写

function identity(arg: string): string {
    return arg;
}

假如函数逻辑相同,但是现在是接收一个number型参数,返回number型参数,则需要在这样写一个

function identity(arg: number): number {
    return arg;
}

逻辑没变,只改变了类型,就需要重新写一个函数,很明显会多出很多重复的代码。其实我们只需要能让使返回值的类型与传入参数的类型是相同就可以了。

这里,我们可以使用一种特殊的变量,类型变量,它只用于表示类型而不是值。

现在我们加类型变量来实现一下我们的需求:

function identity<T>(arg: T): T {
    return arg;
}

可以看到,我们给identity添加了类型变量TT帮助我们捕获用户传入的类型(比如:number),之后我们就可以使用这个类型。 之后我们再次使用了 T当做返回值类型。

现在我们可以知道参数类型与返回值类型是相同的了,这允许我们跟踪函数里使用的类型的信息。

什么是泛型?

我们前面说了这么多,引出了一个类型变量,那和泛型有什么关系呢?

我们把,添加了类型变量T的这个版本的identity函数叫做泛型,因为它可以适用于多个类型。

泛型的使用方式?

定义了泛型之后该怎么使用呢?有两种方式

1、传入所有的参数,包含类型参数

//明确的指定了T是string类型,并做为一个参数传给函数
let output = identity<string>("myString");

image-20220216233118885

注意是:尖括号<>起来而不是圆括号()

2、类型推论(常用)

let output = identity("myString");

image-20220216233421968

类型推论,就是编译器自己根据传入的参数,帮我们确定T的类型。

这样,我们就可以不用尖括号(<>)来明确地传入类型;编译器可以查看myString的值,然后把T设置为它的类型。

泛型约束

从上面来看,泛型似乎可以是任何类型,但如果只希望类型是 number 或者 string 其中之一,该如何处理呢?

我们可以用 <T extends xx> 的方式约束泛型。

image-20220217000302654

这里使用到了 👉 type别名 来进行约束

我们还可以约束泛型必须符合接口的形状描述,比如之前的示例中,它可以使任何【传入参数的类型】和【返回值的类型】相同,但是同时也导致了你必须把这些参数当做是任意或所有类型

什么意思呢?

如以下的两个方法,都是传入参数,试图打印传入参数的长度。

函数identityFun,是正常的,因为它用的是any,表示的是不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查。

函数identity,使用了泛型,它会对传入的参数进行检查。

  • 它可以是任何类型的参数,如果是数组类型,是有length属性。
  • 但是它同样可能是数字类型,而数字类型是没有length属性的,所以如果你想使用传入参数的length属性,检查是不通过的。

image-20220217002023516

如果你的函数必须使用length 属性,你应该在定义一个,包含 length 属性的接口,来进行一个约束。

interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);
    return arg;
}

这样,在调用 loggingIdentity 的时候,传入的 arg 不包含 length的话,在编译阶段就会报错了。

这里用到了 👉 interface接口 来进行约束

设计泛型的关键目的是: 在成员之间提供有意义的约束,这些成员可以是,接口、类的实例成员、类的方法、函数参数、函数返回值

其他

未完待续.....

参考资料:

TS 泛型

TS Playground


🎨【点赞】【关注】不迷路,更多前端干货等你解锁

往期推荐

👉 TypeScript入门之预备知识

👉 TypeScript入门之基础知识

👉 TypeScript入门之进阶篇

👉 TypeScript入门之高级篇