20. TypeScript 类中泛型(难点)

上节我们学习了在函数(方法)中使用泛型的基本语法,这节在看看类中泛型的使用方法。

编写一个基本类

为了下面的教学演示,所以我先编写一个基本的类SelectGirl,在类的构造函数中(constructor)需要传递一组女孩的名称,然后再通过下边展现女孩的名称,代码如下:

class SelectGirl {
  constructor(private girls: string[]) {}
  getGirl(index: number): string {
    return this.girls[index];
  }
}

const selectGirl = new SelectGirl(["小红", "小丽", "小影"]);
console.log(selectGirl.getGirl(1));

写完后,我们可以在终端中使用ts-node Demo.ts进行预览,可以看到控制台中输出了小丽的名字。学到现在你写这样的一个类应该是非常容易的了。

现在问题来了,比如现在更好的保护小姐姐,这些小姐姐使用编号啦,那我们程序要如何修改。需要写成下面的样子,这时候我们代码看起来就没有那么优雅了,在 TypeScript 中,编写复杂代码的时候,会经常使用泛型。

class SelectGirl {
  constructor(private girls: string[] | number[]) {}
  getGirl(index: number): string | number {
    return this.girls[index];
  }
}

初始类的泛型

这时候我们要用泛型重构代码,要如何作那?有了上节课的基础,应该很好理解,就是用<>编写,我们把代码修改成了这个样子。

class SelectGirl<T> {
  constructor(private girls: T[]) {}
  getGirl(index: number): T {
    return this.girls[index];
  }
}

const selectGirl = new SelectGirl(["小红", "小丽", "小影"]);
console.log(selectGirl.getGirl(1));

这时候代码并不报错,也使用了泛型,但是在实例化对象的时候,TypeScript 是通过类型推断出来的。上节已经介绍,这种方法并不好,所以还是需要在实例化对象的时候,对泛型的值进行确定,比如是string类型,就这样写。

const selectGirl = new SelectGirl() < string > ["小红", "小丽", "小影"];

这就是类里边最基础的泛型使用了,如果你还不理解,请现在敲出上面的例子进行练习,不要继续学习了。

泛型中的继承

现在需求又变了,要求返回是一个对象中的name,也就是下面的代码要改成这个样子。

return this.girls[index].name;

现在的代码一定是报错的,但是这时候还要求我们这么做,意思就是说传递过来的值必须是一个对象类型的,里边还要有name属性。这时候就要用到继承了,我用接口的方式来实现。写一个Girl的接口,每个接口里都要有 name 属性。代码如下:

interface Girl {
  name: string;
}

有了接口后用extends关键字实现泛型继承,代码如下:

class SelectGirl<T extends Girl> {
 ...
}

这句代码的意思是泛型里必须有一个name属性,因为它继承了Girl接口。

现在程序还是报错的,因为我们getGirl方法的返回类型还不对,这时候应该是一个string类型才对,所以代码应该改为下面的样子:

interface Girl {
  name: string;
}

class SelectGirl<T extends Girl> {
  constructor(private girls: T[]) {}
  getGirl(index: number): string {
    return this.girls[index].name;
  }
}

const selectGirl = new SelectGirl([
  { name: "小红" },
  { name: "小丽" },
  { name: "小影" },
]);
console.log(selectGirl.getGirl(1));

我们回过头来看一下这段代码的意思,就是我们在SelectGirl类中使用了泛型,意思是我不知道我以后要用什么类型,但是我有一个约束条件,这个类型,必须要有一个name属性。这个在工作中经常使用,所以必须要好好理解这的知识。 初学泛型肯定会很难理解,我当时看书也是看的一脸懵,经过反复的实验和看别人的源代码,才对泛型有了比较深的理解。

泛型约束

现在的泛型可以是任意类型,可以是对象、字符串、布尔、数字都是可以的。但你现在要求这个泛型必须是string或者number类型。我们还是拿上面的例子,不过把代码改为最初的样子。

class SelectGirl<T> {
  constructor(private girls: T[]) {}
  getGirl(index: number): T {
    return this.girls[index];
  }
}

const selectGirl = new SelectGirl<string>(["小红", "小丽", "小影"]);
console.log(selectGirl.getGirl(1));

然后进行约束,这时候还是可以使用关键字extends来进行约束,把代码改成下面的样子。

class SelectGirl<T extends number | string> {
  //.....
}

作为教学泛型讲这些就可以了,但是在实际工作中,泛型的应用更广泛和复杂,这些需要在实际项目中不断精进和加深理解。

「点点赞赏,手留余香」

0

给作者打赏,鼓励TA抓紧创作!

微信微信 支付宝支付宝

还没有人赞赏,快来当第一个赞赏的人吧!

声明:本站所有资源及文章均来源于网络及用户分享或为本站原创,仅限用于学习和研究,任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
码云笔记 » 20. TypeScript 类中泛型(难点)

发表评论

IT互联网行业相关广告投放 更专业 更精准

立即查看 联系我们