一、类型别名
类型别名用来给一个类型起个新名字。
type s = string;
let str: s = "123";
type NameResolver = () => string;:
// 定义了一个类型别名NameResolver,它是一个函数类型。这个函数没有参数,返回值类型为string。这意味着任何被标记为NameResolver的变量都将是一个无参函数,它返回一个字符串。
类型别名常用于联合类型。
type all = string | number | boolean;
let a: all = 2323;
二、字符串字面量类型
type stringType = "ssss" | "wwww" | "rrrr";
let userName: stringType = "rrrr";
let userName2: stringType = "@@@"; // Type '"@@@"' is not assignable to type 'stringType'.
注意,类型别名与字符串字面量类型都是使用 type 进行定义。
三、元组 Tuple
数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象。
let tom: [string, number];
tom[0] = 'Tom';
tom[1] = 25;tom[0].slice(1);
tom[1].toFixed(2);
但是当直接对元组类型的变量进行初始化或者赋值的时候,需要提供所有元组类型中指定的项。
let tom: [string, number];
tom = ['Tom', 25];let tom: [string, number];
tom = ['Tom']; // Property '1' is missing in type '[string]' but required in type '[string, number]'.
当添加越界的元素时,它的类型会被限制为元组中每个类型的联合类型:
let tom: [string, number];
tom = ['Tom', 25];
tom.push('male');
tom.push(true); // Argument of type 'true' is not assignable to parameter of type 'string | number'.
四、枚举
4.1 简单例子
// 使用枚举类型给一组数值赋予名称
// 可以通过 名称去拿值,也可以通过值拿名称
enum NumberType {one,two,three,
}
console.log(NumberType);
4.2 手动赋值
我们也可以给枚举项手动赋值:
enum Days {Sun = 7, Mon = 1, Tue, Wed, Thu, Fri, Sat};console.log(Days["Sun"] === 7); // true
console.log(Days["Mon"] === 1); // true
console.log(Days["Tue"] === 2); // true
console.log(Days["Sat"] === 6); // true
不手动赋值,就默认是从0开始,后面递增
如果未手动赋值的枚举项与手动赋值的重复了,TypeScript 是不会察觉到这一点的:
enum Days {Sun = 3, Mon = 1, Tue, Wed, Thu, Fri, Sat};console.log(Days["Sun"] === 3); // true
console.log(Days["Wed"] === 3); // true
console.log(Days[3] === "Sun"); // false
console.log(Days[3] === "Wed"); // true
手动赋值的枚举项可以不是数字,此时需要使用类型断言来让 tsc 无视类型检查 (编译出的 js 仍然是可用的):
enum Days {Sun = 7, Mon, Tue, Wed, Thu, Fri, Sat = <any>"S"};
var Days;
(function (Days) {Days[Days["Sun"] = 7] = "Sun";Days[Days["Mon"] = 8] = "Mon";Days[Days["Tue"] = 9] = "Tue";Days[Days["Wed"] = 10] = "Wed";Days[Days["Thu"] = 11] = "Thu";Days[Days["Fri"] = 12] = "Fri";Days[Days["Sat"] = "S"] = "Sat";
})(Days || (Days = {}));
当然,手动赋值的枚举项也可以为小数或负数,此时后续未手动赋值的项的递增步长仍为 1:
enum Days {Sun = 7, Mon = 1.5, Tue, Wed, Thu, Fri, Sat};console.log(Days["Sun"] === 7); // true
console.log(Days["Mon"] === 1.5); // true
console.log(Days["Tue"] === 2.5); // true
console.log(Days["Sat"] === 6.5); // true
4.3 常数项和计算所得项
枚举项有两种类型:常数项(constant member)和计算所得项(computed member)。
前面我们所举的例子都是常数项,
一个典型的计算所得项的例子:
enum Color {Red, Green, Blue = "blue".length};
注意,计算所得项必须是最后一项,后面不要再有东西了,因为后面计算不出来
除非后面的有手动赋值
enum Color {red,blue = "blue".length,green = 4,
}
4.4 常数枚举
常数枚举是使用 const enum 定义的枚举类型:
const enum Directions {Up,Down,Left,Right
}let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
常数枚举与普通枚举的区别是,它会在编译阶段被删除,并且不能包含计算成员。
上例的编译结果是:
var directions = [0 /* Up */, 1 /* Down */, 2 /* Left */, 3 /* Right */];
假如包含了计算成员,则会在编译阶段报错:
const enum Color {Red, Green, Blue = "blue".length};// index.ts(1,38): error TS2474: In 'const' enum declarations member initializer must be constant expression.
但是这种是可以的:
const enum Color {Red, Green, Blue = 11};
4.5 外部枚举
主要用在声明文件
外部枚举(Ambient Enums)是使用 declare enum
定义的枚举类型:
declare enum Directions {Up,Down,Left,Right
}let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
之前提到过,declare 定义的类型只会用于编译时的检查,编译结果中会被删除。
上例的编译结果是:
const enum Color {Red, Green, Blue = "blue".length};
var directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
declare 定义的类型只会用于编译时的检查,编译结果中会被删除。
上例的编译结果是:
var directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
同时使用 declare 和 const 也是可以的:
declare const enum Directions {Up,Down,Left,Right
}let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
编译结果:
var directions = [0 /* Up */, 1 /* Down */, 2 /* Left */, 3 /* Right */];
五、类
http://ts.xcatliu.com/advanced/class.html
5.1 属性和方法
// 类:描述了所创建的对象共同的属性和方法
// 实例化对象
class Person {// 首先定义属性name: string;age: number;constructor(name: string, age: number) {this.name = name;this.age = age;}sayHi(str: string) {console.log("hi", str);}
}let p = new Person("slx", 14); // new的时候,回执行构造函数
p.sayHi("slx");
5.2 继承
使用 extends 关键字实现继承,子类中使用 super 关键字来调用父类的构造函数和方法
// 通过继承,扩展现有的类
// 子类继承父类
class Animal {// 父类name: string;age: number;constructor(name: string, age: number) {this.name = name;this.age = age;}sayHi(str: string) {console.log("hi", str);}eat(str: string) {console.log("吃什么呀,吃这个", str);}
}// 子类
class Dog extends Animal {constructor(name: string, age: number) {super(name, age);}// 不写父类的方法,也依然可以调用eat(): void {console.log("子类的eat");super.eat(""); // 当然也可以在里面调用父类的方法}
}const c = new Animal("猫猫", 1);
const d = new Dog("修勾", 3);
d.sayHi("修勾");
d.eat();
类与类之间的存在继承关系,通过extends继承;
子类可以通过super调用父类方法和构造函数;
5.3 存取器
通过getter和setter 可以改变属性的赋值和读取行为,控制对对象成员的访问
class Name {firstName: string;lastName: string;constructor(firstName: string, lastName: string) {this.firstName = firstName;this.lastName = lastName;}get fullName() {return this.firstName + "-" + this.lastName;}
}let n = new Name("张", "凌");
console.log(n);