1、字符串字面量类型
字符串字面量类型用来约束取值只能是某几个字符串中的一个
2、元祖(Tuple)
数组:同一类型的集合
元祖:不同类型的集合
3、枚举(Enum)
枚举使用 enum 关键字来定义
枚举成员会被赋值为从 0 开始递增的数字,同时也会对枚举值到枚举名进行反向映射
console.log(Colors['White']) // 0
console.log(Colors['Black']) // 1
console.log(Colors['Red']) // 2
可以给枚举项手动赋值:
eunm Colors {White = 7, Black = 2, Red}
console.log(Colors['White']) // 7
console.log(Colors['Black']) // 2
// 未手动赋值的枚举项会接着上一个枚举项递增
console.log(Colors['Red']) // 3
未手动赋值的枚举项与手动赋值的重复时,会被后赋值的那一次覆盖。
上面的例子都是常数项,下面是一个计算所得项的例子:
注意:如果紧接在计算所得项后面的是未手动赋值的项,那么它就会因为无法获得初始值而报错
常数枚举
常数枚举使用 const enum
定义,不能包含计算成员
const enum Colors {
White,
Black,
Red
}
外部枚举
外部枚举使用 declare enum
定义,常出现在声明文件中,declare
定义的类型只会用于编译时的检查,编译结果中会被删除
4、类
TypeScript可以使用三种访问修饰符(修饰属性或方法):
- public:修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是public的
- private:修饰的属性或方法是私有的,不能在声明它的类的外部访问;当构造函数修饰为 private 时,该类不允许被继承或者实例化
- protected:修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的;当构造函数修饰为 protected 时,该类只允许被继承
以上三种修饰符和readonly关键字还可以用在构造函数的参数中,等同于类中定义该属性并同时给该属性赋值
class Animal {
// public name: string;
public constructor(public name) {
// this.name = name;
}
}
readonly关键字
只读属性关键字,只允许出现在属性声明或索引签名或构造函数中。
readonly 和其他访问修饰符同时存在的话,需要写在其后面。
class Animal {
readonly name;
public constructor(name) {
this.name = name;
}
}
let a = new Animal('Jack');
console.log(a.name); // Jack
a.name = 'Tom';
// index.ts(10,3): TS2540: Cannot assign to 'name' because it is a read-only property.
抽象类
使用abstract定义抽象类和其中的抽象方法,抽象类不允许被实例化,抽象类中的抽象方法必须被子类实现
abstract 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');
给类加上TS的类型
class Aniaml {
name: string,
constructor(name: string) {
this.name = name
}
sayHi(): string {
return 'Hello'
}
}
let cat: Animal = new Animal('Tom')
console.log(cat.sayHi())
5、类与接口
接口的两个作用:
- 用于对对象的形状进行描述
- 对类的一部分进行抽象
类实现接口(implements)
interface Alarm {
alert(): void;
}
interface Light {
lightOn(): void;
lightOff(): void;
}
class Car implements Alarm, Light {
alert() {
console.log('Car alert');
}
lightOn() {
console.log('Car light on');
}
lightOff() {
console.log('Car light off');
}
}
接口继承接口
interface Alarm {
alert(): void;
}
interface LightableAlarm extends Alarm {
lightOn(): void;
lightOff(): void;
}
接口继承类
在Java等面向对象的语言中,接口是不能继承类的,但是在TypeScript中可以:
class Point {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
}
interface Point3d extends Point {
z: number;
}
let point3d: Point3d = {x: 1, y: 2, z: 3};
接口继承类,实际上也是接口继承接口。
实际上,当我们声明class Point
的时候,会同时做这件事:
- 创建一个名为Point的类
- 创建一个名为Point的类型
所以我们既可以将Point当作一个类来用:
也可以将Point当作一个类型来用:
在上面的例子中,interface Point3d extends Point
Point3d继承的实际上是Point的实力的类型,可以按下面这个例子理解: Point3d 继承另一个接口 PointInstanceType
class Point {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
}
interface PointInstanceType {
x: number;
y: number;
}
// 等价于 interface Point3d extends PointInstanceType
interface Point3d extends Point {
z: number;
}
let point3d: Point3d = {x: 1, y: 2, z: 3};
注意:声明 Point 类时创建的 Point 类型只包含其中的实例属性和实例方法。同样的,在接口继承类的时候,也只会继承它的实例属性和实例方法。
6、泛型
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
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>
多个类型参数
function swap<T, U>(tuple: [T, U]): [U, T] {
return [tuple[1], tuple[0]];
}
swap([7, 'seven']); // ['seven', 7]
在函数内部使用泛型变量的时候,由于事先不知道它是哪种类型,所以不能随意的操作它的属性或方法,这时,我们可以对泛型进行约束,只允许这个函数传入那些包含该属性的变量。这就是泛型约束:
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}