课程地址:【黑马程序员前端TypeScript教程,TypeScript零基础入门到实战全套教程】 https://www.bilibili.com/video/BV14Z4y1u7pi/?share_source=copy_web&vd_source=b1cb921b73fe3808550eaf2224d1c155
目录
4、TypeScript高级类型
- ts高级类型很多,主要学习以下内容
- class类
- js已经有class;
- ts为class提供类型注解,以及其他新功能
- 类型兼容性
- 不算是类型,而是ts中类型之间的关系,偏原理性
- 交叉类型
- 写法类似联合类型
- 泛型和keyof
- 重要
- 泛型让函数和接口更加通用
- keyof运算符
- 索引签名类型和索引查询类型
- 与索引相关的类型
- 映射类型
- 可以根据已有类型实现新类型
- class类
4.1 class类
es6引入了class,用来在js中实现面向对象。
TypeScript 全面支持 ES2015 中引入的 class 关键字,并为其添加了类型注解和其他语法(比如,可见性修饰符等) 。
4.1.1 class基本使用
ts的class与js中的定义是一样的,都是class关键字 类名 花括号{}。
创建实例对象,new 类名() 创建实例对象。
class Person{ }
const p1 = new Person();
解释:
1. 根据 TS 中的类型推论,可以知道 Person 类的实例对象 p 的类型是 Person类。
2. TS 中的 class,不仅提供了 class 的语法功能,也作为一种类型存在。
4.1.2 给类添加属性
class Person{
name: string // 方法1(只为Person类指定了name属性,该属性没有默认值
age = 18 // 方法2,有默认值的属性,可以省略属性的类型不写。
}
解释:
1. 声明成员 age,类型为 number(没有初始值)。
2. 声明成员 gender,并设置初始值,此时,可省略类型注解(TS 类型推论 为 string 类型)
给类添加实例成员,实例成员是通过实例对象访问的,比如p1.age,p1.name。
4.1.3 构造函数constructor
构造函数的作用,为类的属性设置初始值。
class Person{
name: string; // 方法1(只为Person类指定了name属性,该属性没有默认值
age: number;
// 构造函数
constructor(name: string, age: number) {
this.name = name;
this.age = age
}
}
const p1 = new Person('zyy', 18);
解释:
1. 成员初始化(比如,age: number)后,才可以通过 this.age 来访问实例成员。
2. 需要为构造函数的参数指定类型注解,否则会被隐式推断为 any;构造函数不需要返回值类型。
4.1.4 实例方法
实例方法和实例属性一样,都是通过实例对象来访问的。
class Person{
name: string;
age: number;
// 实例方法
scale(n: number): void {
this.age = n;
}
}
解释:方法的类型注解(参数和返回值)与函数用法相同。
4.1.5 继承
ts中类继承的两种方式:1 extends(继承父类) 2 implements(实现接口)。
说明:JS 中只有 extends,而 implements 是 TS 提供的。
4.1.5.2 继承父类extends
解释:
1. 通过 extends 关键字实现继承。
2. 子类 Dog 继承父类 Animal,则 Dog 的实例对象 dog 就同时具有了父类 Animal 和 子类 Dog 的所有属性和方法。
接口继承也是通过extends实现的。
4.1.5.2 实现接口implements
解释:
1. 通过 implements 关键字让 class 实现接口。
2. Person 类实现接口 Singable 意味着,Person 类中必须提供 Singable 接口中指定的所有方法和属性。
4.1.6 类的可见性修饰符
类成员可见性:可以使用 TS 来控制 class 的方法或属性对于 class 外的代码是否可见。
可见性修饰符(控制类成员的可见性)包括:
1 public(公有的)
2 protected(受保护的)
3 private(私有的)。
4.1.6.1 public
1. public:表示公有的、公开的,公有成员可以被任何地方访问,默认可见性。
解释:
1. 在类属性或方法前面添加 public 关键字,来修饰该属性或方法是公有的。
2. 因为 public 是默认可见性,所以,可以直接省略。
4.1.6.2 protected
2. protected:表示受保护的,仅对其声明所在类和子类中(非实例对象)可见。
注意:仅对当前类和子类可见,类的实例对象不可见。
- Animal的move方法是protected的,那么move方法只能在①当前类Animal和②Animal的子类中可见,③类的实例对象不可见。
- ①如果Animal还有其他的方法,那么是可以调用move方法的。
- ②如果子类继承了Animal,那么在子类的方法中也可以通过this来调用Animal类中提供的move方法。
- ③不管是Animal的实例对象还是子类Dog的实例对象,move方法都是不可见的。
解释:
1. 在类属性或方法前面添加 protected 关键字,来修饰该属性或方法是受保护的。
2. 在子类的方法内部可以通过 this 来访问父类中受保护的成员,但是,对实例对象不可见。
4.1.6.3 private
3. private:表示私有的,只在当前类中可见,对实例对象以及子类以及子类的实例对象都是不可见的。
解释:
1. 在类属性或方法前面添加 private 关键字,来修饰该属性或方法是私有的。
2. 私有的属性或方法只在当前类中可见,对子类和实例对象也都是不可见的!
4.1.7 类的常见修饰符readonly
除了可见性修饰符之外,还有一个常见修饰符就是:readonly(只读修饰符)。
readonly:表示只读,用来防止在构造函数之外对属性进行赋值。
解释:
1. 使用 readonly 关键字修饰该属性是只读的。该属性变成只读后,就只能在构造函数constructor里为age属性设置初始值,其他方法里不能对age值进行修改。注意只能修饰属性不能修饰方法。
readonly age: number = 18,这里相当于属性age的默认值,也可以不设置默认值。
readonly修饰的属性,允许有默认值。
可以在构造函数里对只读的属性进行赋值,除此之外都是不允许的。
2. 注意:属性 age 后面的类型注解(比如,此处的 number)如果不加,则 age 的类型为 18 (字面量类型)。
3. 接口或者 {} 表示的对象类型,也可以使用 readonly。(这里p42给出例子了,但是我没听)
4.2 类型兼容性
类型兼容性不是指某一个高级类型,而是ts中类型系统中的特性。
理解了类型兼容性,才掌握了ts的类型系统。
4.2.1 类型兼容性的说明
1 什么是类型兼容性
举个例子
let arr = ['a', 'b', 'c'];
arr.forEach(item => { });
这里,forEach接受回调函数作为参数。
注意:在传入回调函数时就已经发生了类型兼容性。
其实就是回调函数发生了类型兼容性。
回调函数有3个入参,没有返回值。但是forEach的回调函数参数只有一个参数item,赋值给了具有三个参数的回调函数类型。从参数数量上来看,这两个参数是不一致的。
但是这样在ts中代码没有报错。因为此时就发生了类型兼容性。这就是为什么说类型兼容性在实际coding时经常遇到,但是咱们很少注意这个。
为什么会有类型兼容性呢,与js的特性有关。在js中调用forEach函数时,经常传一个参数,不需要指定所有的参数。这种做法已经持续了很长时间了,因为ts在设计类型时就考虑到这点了,而这一点就是类型兼容性。
当然不只可以传入一个参数,还可以传入两个或三个参数。
arr.forEach(item => { });
arr.forEach((item, index) => { });
arr.forEach((item, index, array) => { });
以上三种写法都是可以的,在ts中因为类型兼容性,所以可以这样写。
2 理解类型兼容性
两种类型系统:1 Structural Type System(结构化类型系统) 2 Nominal Type System(标明类型系统)。
TS 采用的是结构化类型系统,也叫做 duck typing(鸭子类型),类型检查关注的是值所具有的形状。
也就是说,在结构类型系统中,如果两个对象具有相同的形状,则认为它们属于同一类型。
鸭子类型:如果一个东西叫起来像鸭子,走路像鸭子,游泳像鸭子,那么这个东西就是一个鸭子。这就是所说的鸭子类型,也叫做鸭子辨型。
例子