typescript 学习之路进阶版
类型别名
1 | type Name = string; |
类型别名为类型创建新名称。类型别名有时类似于接口,但是可以命名原语,并集,元祖和其他必须手动编写的其他类型。
别名实际上并不会创建新的类型,他会创建一个新名称来引用该类型1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24type Container<T> = {value: T}
// 也可以在属性中使用类型别名来引用自身
type Tree<T> = {
value: T;
left: Tree<T>;
right: Tree<T>;
}
// 与交叉点类型一起使用
type LinkedList<T> = T & {next: LinkedList<T>}
interface Person {
name: string
}
var people: LinkedList<Person>
var s = people.name
var s = people.next.name
var s = people.next.next.name
var s = people.next.next.next.name
// 但是类型别名不可能出现在声明右侧的任何其他位置
字符串字面量类型
1 | type EventNames = 'click' | 'scroll' | 'mousemove' |
我们使用type定了一个字符串字面量类型EventNames
, 它只能取三种字符串中的一种
类型别名与字符串字面量类型都是使用type
进行定义
可以使用相同的方式使用字符串文字类型来区分重载1
2
3
4
5function createElement(tagName: 'img'): HTMLImageElement
function createElement(tagName: 'input'): HTMLIputElement
function createElement(tagName: 'string'): Element {
}
元组
数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象
eg:1
let tom: [string, number] = ['Tom', 25]
当赋值或访问一个已知的索引元素时,会得到正确的类型
也可以只赋值其中一项
1 | let tom: [string, number] |
如果直接对元组类型的变量进行初始化或者赋值的时候,需要提供所有的元组类型中指定的项
当添加越界的元素时,它的类型会被限制为元组的每个类型的联合类型
枚举 Enum
枚举类型用于取值被限定在一定范围内的场景,比如一周只能有七天,颜色限定为红绿蓝等
eg:
枚举定义 使用enum
定义1
2
3
4
5
6
7enum Days {Sun, Mon, Tue, Web, Thu, Fri, Sat}
// 枚举成员会被赋值从0开始递增的数字,同时也会对枚举值到枚举名进行反向映射
Days['Sun'] === 0 // true
Days[0] === 'Sun' // true
手动赋值
我们也可以手动给枚举项赋值
1 | enum Days {Sun = 7, Mon = 1, Tue, Wed, Thu, Fri, Sat} |
如果手动赋值的枚举项与自动赋值的枚举项重复了,并不会报错
手动赋值的枚举项可以不是数字,但是需要使用类型断言来无视类型检查
常数项和计算所得项
枚举有两种类型: 常数项和计算所得项
1 | enum Color {Red, Green, Blue = 'blue'.length} |
上面 'blue'.length
就是一个计算所得项
如果紧接在计算所得项后面是未手动赋值的项,那么会因为无法获得初始值而报错
常数枚举
1 | const enum Directions { |
常数枚举与普通枚举的区别是,它会在编译阶段被删除,并且不能包含计算成员
上述编译的结果是:
1 | var directions = [0 /* Up */ , 1 /* Up */, 2 /* Up */, 3 /* Up */] |
如果在定义的时候包含了计算成员,则会在编译阶段报错
外部枚举
外部枚举 是使用declare enum
定义的枚举类型
1 | declare enum Directions { |
同时使用declare
和const
也是可以的
类
类的概念
类:定义了一件事物的抽象特点,包含他的属性和方法
对象:类的实例,通过new生成
面对对象(OPP)三大特性: 封装、继承、多态
封装(Encapsulation):将对数据的操作细节隐藏起来,质保楼对外的接口,外界调用端不需要知道细节,就能通过对外提供的接口来访问该对象,同时也保证了外界无法任意更改对象内部的数据
继承(Inheritance):子类继承父类,子类除了拥有父类的所有特性外,还有一些更具体的特性
多态(Poluymorphism):由继承而产生的不同的类,对同一个方法可以有不同的响应,程序会自动判断应该如何执行
存取器(getter & setter): 用于改变属性的读取和赋值行为
修饰符(Modifiers): 修饰符是一些关键字,用于限定成员或类型的性质,比如
public
表示共有属性和方法抽象类(Abstract Class): 抽象类是供其他继承的基类,抽象类不允许被实例化,抽象类中的抽象方法必须在子类中被实现
接口(interface): 不同类之间巩固偶的属性和方法可以抽象成一个接口,接口可以被类实现,一个类只能继承自另一个类,但是可以实现多个接口
ES6中类的用法
属性和方法
使用class
定义类,使用constructor
定义构造函数
通过new
生成新实例的时候,会自动带调用构造函数
类的继承
使用extends
关键字实现继承,子类通过super
关键字调用父类的构造函数和方法
1 | class Cat extends Animal { |
存取器
使用getter和setter可以改变属性的赋值和读取行为
1 | class Animal { |
静态方法
使用static
修饰符修饰的方法称为静态方法,不需要实例化,而是直接通过类来调用
1 | class Animal { |
ES7中类的用法
实例属性
ES6中实例的属性只能通过构造函数中的this.xxx
来定义,ES7可以直接在类里面定义
1 | // ES7 |
静态属性
可以用static
定义一个静态属性
1 | // ES7 |
TypeScript中使用类
public private和protect
TypeScript中可以使用三种访问修饰符分别是public
,private
,protected
public
修饰的属性或方法是共有的,可以在任何地方被访问,默认所有的属性和方法都是public
的private
修饰的属性和方法是私有的,不能在声明它的类的访问’protected
修饰的属性和方法是受保护的,它和private
类似,区别是在子类中也是允许被访问的当构造函数
constructor
修饰为private
时,该类不允许被继承或者实例化
当构造函数constructor
修饰为protected
时, 该类只允许被继承参数属性
修饰符和
readonly
还可以使用构造函数参数中,等同于类中定义该属性的同时给该属性赋值,使代码更简洁1
2
3
4
5class Animal {
public construtor(public name) {
// 等同于 this.name = name
}
}readonly
只读属性关键字,只允许出现在属性声明或索引签名或构造函数中
如果readonly
和其他修饰符同时存在的话,需要写在后面抽象类
abstract
用于定义抽象类和其中的抽象方法抽象类是不允许被实例化的
如果定义了一个抽象类,并且定义了一个抽象方法
sayHi
, 在实例化抽象类的时候报错抽象类中的抽象方法必须被子类实现,如果继承了抽象类,却没有实现抽象类中的抽象方法,就是编译报错
正确使用抽象类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15abstract class Animal {
public name;
public constructor(name) {
this.name = name;
}
public abstract sayHi();
}
class Cat extends Animal {
public sayHi() {
console.log(`Meow, My name is ${this.name}`);
}
}
let cat = new Cat('Tom');类的类型
给类加上TypeScript的类型1
2
3
4
5
6
7
8
9
10
11
12class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
sayHi(): string {
return `My name is ${this.name}`;
}
}
let a: Animal = new Animal('Jack');
console.log(a.sayHi()); // My name is Jack