title: typescript学习(二)categories: TS
tag: TypeScript
date: 2021-10-17 14:42:34

类型缩小

什么是类型缩小呢?

  • 类型缩小的英文是 Type Narrowing;

  • 我们可以通过类似于 typeof padding === “number” 的判断语句,来改变TypeScript的执行路径;

  • 在给定的执行路径中,我们可以缩小比声明时更小的类型,这个过程称之为 缩小;

  • 而我们编写的 typeof padding === “number 可以称之为 类型保护(type guards);

常见的类型保护有如下几种:

  1. typeof

  2. 平等缩小(比如===、!==)

  3. instanceof

  4. in

1. typeof

在 TypeScript 中,检查返回的值typeof是一种类型保护:因为 TypeScript 对如何typeof操作不同的值进行编码。

image-20211017164240547

2. 平等缩小

我们可以使用Switch或者相等的一些运算符来表达相等性(比如===, !==, ==, and != ):

2021-10-17-typescript学习(二) - 图2

3. instanceof

JavaScript 有一个运算符来检查一个值是否是另一个值的“实例”:

2021-10-17-typescript学习(二) - 图3

4. in

Javascript 有一个运算符,用于确定对象是否具有带名称的属性:in运算符

  • 如果指定的属性在指定的对象或其原型链中,则in 运算符返回true;

2021-10-17-typescript学习(二) - 图4

认识类的使用

我们来定义一个Person类:

使用class关键字来定义一个类;

我们可以声明一些类的属性:在类的内部声明类的属性以及对应的类型

  • 如果类型没有声明,那么它们默认是any的;

  • 我们也可以给属性设置初始化值;

  • 在默认的strictPropertyInitialization模式下面我们的属性是必须初始化的,如果没有初始化,那么编译时就会报错;

    • 如果我们在strictPropertyInitialization模式下确实不希望给属性初始化,可以使用 name!: string语法;

类可以有自己的构造函数constructor,当我们通过new关键字创建一个实例时,构造函数会被调用;

  • 构造函数不需要返回任何值,默认返回当前创建出来的实例;

  • 类中可以有自己的函数,定义的函数称之为方法;

2021-10-17-typescript学习(二) - 图5

类的继承

面向对象的其中一大特性就是继承,继承不仅仅可以减少我们的代码量,也是多态的使用前提。

我们使用extends关键字来实现继承,子类中使用super来访问父类。

我们来看一下Student类继承自Person:

  • Student类可以有自己的属性和方法,并且会继承Person的属性和方法;

  • 在构造函数中,我们可以通过super来调用父类的构造方法,对父类中的属性进行初始化;

2021-10-17-typescript学习(二) - 图6

使用super关键字

  1. class Person{
  2. name:string
  3. age:number
  4. constructor(name:string,age:number){
  5. this.name=name
  6. this.age=age
  7. }
  8. eating(){
  9. console.log('eating');
  10. }
  11. }
  12. class Student extends Person{
  13. sno:number
  14. constructor(name:string,age:number,sno:number){
  15. //调用父类构造器
  16. super(name,age)
  17. this.sno=sno
  18. }
  19. studying(){
  20. console.log('studying');
  21. }
  22. }
  23. //此时学生也是有name属性的
  24. const stu=new Student('donghuan',22,111)
  25. console.log(stu.name);

也可以通过super调用

  1. //方法的重写
  2. eating(){
  3. super.eating()
  4. console.log('student eating');
  5. }
  6. }
  7. //此时学生也是有name属性的
  8. const stu=new Student('donghuan',22,111)
  9. stu.eating()

类的成员修饰符

在TypeScript中,类的属性和方法支持三种修饰符: public、private、protected

  • public 修饰的是在任何地方可见、公有的属性或方法,默认编写的属性就是public的;

  • private 修饰的是仅在同一类中可见、私有的属性或方法;

  • protected 修饰的是仅在类自身及子类中可见、受保护的属性或方法;

public是默认的修饰符,也是可以直接访问的,我们这里来演示一下protected和private。

private的使用

2021-10-17-typescript学习(二) - 图7

protected的使用

2021-10-17-typescript学习(二) - 图8

只读属性readonly

如果有一个属性我们不希望外界可以任意的修改,只希望确定值后直接使用,那么可以使用readonly。仅仅属性本身不能修改。但是如果是对象。是可以修改这个对象的属性

2021-10-17-typescript学习(二) - 图9

getters和setters

2021-10-17-typescript学习(二) - 图10

类的静态成员

前面我们在类中定义的成员和方法都属于对象级别的, 在开发中, 我们有时候也需要定义类级别的成员和方法。

在TypeScript中通过关键字static来定义:

  1. class Person{
  2. static time:string="22:00"
  3. static attend(){
  4. console.log('attend');
  5. }
  6. }
  7. //不需要new出来对象,直接访问就可以了
  8. console.log(Person.time);
  9. Person.attend()

抽象类

我们知道,继承是多态使用的前提。

所以在定义很多通用的调用接口时, 我们通常会让调用者传入父类,通过多态来实现更加灵活的调用方式。

但是,父类本身可能并不需要对某些方法进行具体的实现,所以父类中定义的方法,,我们可以定义为抽象方法。

什么是 抽象方法? 在TypeScript中没有具体实现的方法(没有方法体),就是抽象方法。

  • 抽象方法,必须存在于抽象类中

  • 抽象类是使用abstract声明的类;

抽象类有如下的特点:

  • 抽象类是不能被实例的(也就是不能通过new创建)

  • 抽象方法必须被子类实现,否则该类必须是一个抽象类

2021-10-17-typescript学习(二) - 图11

类的类型

类本身也是可以作为一个数据类型的

2021-10-17-typescript学习(二) - 图12

接口的声明

在前面我们通过type可以用来声明一个对象类型:

2021-10-17-typescript学习(二) - 图13

对象的另外一种声明方式就是通过接口来声明:

2021-10-17-typescript学习(二) - 图14

可选属性

我们可以定义可选属性。

2021-10-17-typescript学习(二) - 图15

只读属性

接口中也可以定义只读属性:

  • 这样就意味着我们再初始化之后,这个值是不可以被修改的;

2021-10-17-typescript学习(二) - 图16

索引类型

2021-10-17-typescript学习(二) - 图17

函数类型

前面我们都是通过interface来定义对象中普通的属性和方法的,实际上它也可以用来定义函数类型

2021-10-17-typescript学习(二) - 图18

当然,其实还是用类型别名来定义函数好一点

2021-10-17-typescript学习(二) - 图19

接口继承

接口和类一样是可以进行继承的,也是使用extends关键字:

并且接口是支持多继承的。(类不支持多继承)

2021-10-17-typescript学习(二) - 图20

接口的实现

接口定义后,也是可以被类实现的:

  • 如果被一个类实现,那么在之后需要传入接口的地方,都可以将这个类传入;

  • 这就是面向接口开发;

2021-10-17-typescript学习(二) - 图21

interface和type的区别

我们会发现interface和type都可以用来定义对象类型,那么在开发中定义对象类型时,到底选择哪一个呢?

  • 如果是定义非对象类型,通常推荐使用type,比如Direction、Alignment、一些Function;

如果是定义对象类型,那么他们是有区别的:

  • interface 可以重复的对某个接口来定义属性和方法;

  • 而type定义的是别名,别名是不能重复的;

字面量赋值

这是因为TypeScript在字面量直接赋值的过程中,为了进行类型推导会进行严格的类型限制。

但是之后如果我们是将一个 变量标识符 赋值给其他的变量时,会进行freshness擦除操作。

2021-10-17-typescript学习(二) - 图22

认识泛型

软件工程的主要目的是构建不仅仅明确和一致的API,还要让你的代码具有很强的可重用性:

  • 比如我们可以通过函数来封装一些API,通过传入不同的函数参数,让函数帮助我们完成不同的操作;

  • 但是对于参数的类型是否也可以参数化呢?

什么是类型的参数化?

我们来提一个需求:封装一个函数,传入一个参数,并且返回这个参数;

如果我们是TypeScript的思维方式,要考虑这个参数和返回值的类型需要一致:

2021-10-17-typescript学习(二) - 图23

上面的代码虽然实现了,但是不适用于其他类型,比如string、boolean、Person等类型:

2021-10-17-typescript学习(二) - 图24