TS进阶知识点

类型别名

type给类型起一个新名字,常用于联合类型。

同时也可以用type定义字符串字面量让其只能在其中三种字符串取值👇

1
2
3
4
type EventNames = 'click' | 'scroll' | 'mousemove';
function handleEvent(ele: Element, event: EventNames) {
// do something
}

元组

数组合并了相同类型的对象,元组可以合并不同类型的对象

1
let tom: [string, number] = ['Tom', 25];

定义一对值分别为 stringnumber 的元组。初始化或者赋值的时候,需要提供所有元组类型中指定的项

当添加越界的元素时,类型会被限制为元组中的联合类型

枚举

用于取值被限定在一定范围内,比如一周只有七天。使用enum

枚举成员会被赋值为从 0 开始递增的数字,同时也会对枚举值到枚举名进行反向映射:

1
2
3
4
5
6
7
enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};

console.log(Days["Sun"] === 0); // true
console.log(Days["Mon"] === 1); // true

console.log(Days[0] === "Sun"); // true
console.log(Days[1] === "Mon"); // true

手动赋值

1
enum Days {Sun = 7, Mon = 1, Tue, Wed, Thu, Fri, Sat};

未手动赋值的枚举项会接着上一个枚举项递增,未手动赋值的枚举项会接着上一个枚举项递增

但如果重复了,TS不能察觉,重复的值会被覆盖

常数项和计算所得项

枚举项有两种:常数项和计算所得项

1
enum Color {Red, Green, Blue = "blue".length};

"blue".length 就是一个计算所得项,注意写法的顺序,计算所得项后面的是未手动赋值的项,那么它就会因为无法获得初始值而报错

常数枚举

使用 const enum 定义,常数枚举与普通枚举的区别是,它会在编译阶段被删除,并且不能包含计算成员

外部枚举

declare enum 定义,外部枚举与声明语句一样,常出现在声明文件中。

类的相关概念

  • 类(Class):定义了一件事物的抽象特点,包含它的属性和方法
  • 对象(Object):类的实例,通过 new 生成
  • 面向对象(OOP)的三大特性:封装、继承、多态
  • 封装(Encapsulation):将对数据的内部逻辑隐藏起来,只暴露一个接口。外界调用不需要(也不可能)知道细节,就能通过接口来访问对象,同时也保证了外界无法任意更改对象内部的数据
  • 继承(Inheritance):子类继承父类,子类除了拥有父类的所有特性外,还有一些自己的特性
  • 多态(Polymorphism):继承自同一个父类的不同子类,对同一个方法有不同的响应。比如 CatDog 都继承自 Animal,但是分别实现了自己的 eat 方法。此时针对某一个实例,我们无需了解它是 Cat 还是 Dog,就可以直接调用 eat 方法,程序会自动判断出来应该如何执行 eat
  • 存取器(getter & setter):用以改变属性的读取和赋值行为
  • 修饰符(Modifiers):修饰符是一些关键字,用于限定成员或类型的性质。比如 public 表示公有属性或方法
  • 抽象类(Abstract Class):抽象类是供其他类继承的基类,抽象类不允许被实例化。抽象类中的抽象方法必须在子类中被实现
  • 接口(Interfaces):不同类之间公有的属性或方法,可以抽象成一个接口。接口可以被类实现(implements)。一个类只能继承自另一个类,但是可以实现多个接口。

ES6中类的用法

使用 class 定义类,使用 constructor 定义构造函数。通过 new 生成新实例的时候,会自动调用构造函数。

使用 extends 关键字实现继承,子类中使用 super 关键字来调用父类的构造函数和方法。

存取器,使用getter和setter改变属性的赋值和读取行为。

静态方法,指使用static修饰的方法,不需实例化,可直接通过类调用。

静态方法作用:在创建类的时候就已经存在内存中,直到程序结束才销毁,不用在每一个实例化中反复创建,节约内存空间

ES7中类的用法

实例属性:ES6中实例属性只能通过构造函数的this.xxx定义,ES7中可以通过在类中直接定义。

1
2
3
4
5
6
class Animal {
name = 'Jack';
constructor() {
// ...
}
}

静态属性:可以用static定义一个静态属性。

TS中类的用法

修饰符:

  • public:修饰公有属性和方法,默认所有属性和方法都是public
  • private:修饰私有属性和方法,不能在类的外部访问
  • protected:修饰属性和方法受保护,但是可以被子类访问

当构造函数为private时,不允许被继承或实例化,为protected时,只能被继承。

修饰符和readonly还可以用在构造函数参数中=在类中定义该属性并赋值

1
2
3
4
5
6
class Animal {
// public name: string;
public constructor(public name) {
// this.name = name;
}
}

抽象类:

abstract来是声明,抽象类不能被实例化,只能继承,子类中必须实现抽象方法。

类的类型:

可以给类加上TS类型

类与接口

一个类可以实现多个接口,接口是一些类之间公共方法和属性的抽象,接口可以继承接口。在TS中,接口可以继承类。因为在TS中,创建一个类的同时也创建了一个类型

泛型

指在定义函数、接口或类的时候,不预先指定具体类型,而是在使用时再指定。

1
2
3
4
5
6
7
8
9
function createArray<T>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}

createArray<string>(3, 'x'); // ['x', 'x', 'x']

函数名后添加了 <T>T指可以输入任何类型的值,Array数组中的每一项都是输入的value的类型

泛型约束:在函数内部使用泛型的时候,由于事先并不知道具体的类型,有的属性和方法不能随意使用

1
2
3
4
5
function loggingIdentity<T>(arg: T): T {
console.log(arg.length);
return arg;
}
// index.ts(2,19): error TS2339: Property 'length' does not exist on type 'T'.

泛型T不一定包含属性length,要对泛型进行约束,只允许变量包含特定的(如length)属性才能传入。

1
2
3
4
5
6
7
8
interface Lengthwise {
length: number;
}

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

泛型可以用在接口和类上

声明合并

当定义了两个相同名字的函数、类、接口时,会合并成一个类型。

查看评论