typescript_learning

TypeScript,转自legacy的gitbook

安装编译

1
2
npm install -g typescript
tsc hello.ts

tsc 对类型做静态检查,如果有错误,编译会报错,但会继续生成编译结果

基础

  1. 原始数据类型
  • 布尔值
1
let isDone: boolean = false;
  • null类型 和 undefined类型,他俩是所有类型的子类型,即可以赋值给其他类型
1
2
let u: undefined = undefined;
let n: null = null;
  • 数值
1
2
3
4
5
6
7
8
9
let decLiteral: number = 6;
// 16 进制
let hexLiteral: number = 0xf00d;
// ES6 中的二进制表示法
let binaryLiteral: number = 0b1010;
// ES6 中的八进制表示法
let octalLiteral: number = 0o744;
let notANumber: number = NaN;
let infinityNumber: number = Infinity;
  • 字符串
1
2
3
4
5
6
let myName: string = 'Tom';
let myAge: number = 25;

// 模板字符串
let sentence: string = `Hello, my name is ${myName}.
I'll be ${myAge + 1} years old next month.`;
  • 空值, 用于函数返回值
1
2
3
function alertName(): void {
alert('My name is Tom');
}
  • 任意类型
1
2
let myFavoriteNumber: string = 'seven';
myFavoriteNumber = 7;
  • 联合类型
1
2
3
let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
  1. 对象的类型
  • 接口
1
2
3
4
5
6
7
8
9
interface Person {
name: string;
age: number;
}

let tom: Person = {
name: 'Tom',
age: 25
};
  • 可选属性,带?
1
2
3
4
5
6
7
8
interface Person {
name: string;
age?: number;
}

let tom: Person = {
name: 'Tom'
};
  • 任意属性
1
2
3
4
5
6
7
8
9
10
interface Person {
name: string;
age?: number;
[propName: string]: any;
}

let tom: Person = {
name: 'Tom',
gender: 'male'
};

使用 [propName: string] 定义了任意属性取 string 类型的值。

需要注意的是,一旦定义了任意属性,那么确定属性和可选属性都必须是它的子属性

  • 只读属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
interface Person {
readonly id: number;
name: string;
age?: number;
[propName: string]: any;
}

let tom: Person = {
id: 89757,
name: 'Tom',
gender: 'male'
};

tom.id = 9527;

// index.ts(14,5): error TS2540: Cannot assign to 'id' because it is a constant or a read-only property.

上例中,使用 readonly 定义的属性 id 初始化后,又被赋值了,所以报错了。

注意,只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候

  1. 数组类型
  • 基本数组
1
let fibonacci: number[] = [1, 1, 2, 3, 5];
  • 泛型数组
1
let fibonacci: Array<number> = [1, 1, 2, 3, 5];
  1. 函数类型
1
2
3
4
5
6
7
8
9
// 函数声明(Function Declaration)
function sum(x, y) {
return x + y;
}

// 函数表达式(Function Expression)
let mySum = function (x, y) {
return x + y;
};
  1. 类型断言
1
2
3
4
5
6
7
function getLength(something: string | number): number {
if ((<string>something).length) {
return (<string>something).length;
} else {
return something.toString().length;
}
}
  1. 声明文件
1
2
3
4
// jQuery.d.ts
declare var jQuery: (string) => any;

jQuery('#foo');
  1. 内置对象
  • ECMAScript内置对象,在typescript核心库中已经定义好了,还扩展了内置对象,如DOM、BOM等

  • 其他第三方,如node,可以用npm来生成

1
npm install @types/node --save-dev

进阶

  1. 类型别名,关键词type
1
2
3
4
5
6
7
8
9
10
11
type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
function getName(n: NameOrResolver): Name {
if (typeof n === 'string') {
return n;
}
else {
return n();
}
}
  1. 字符串字面量类型,关键词type
1
2
3
4
5
6
7
type EventNames = 'click' | 'scroll' | 'mousemove';
function handleEvent(ele: Element, event: EventNames) {
// do something
}

handleEvent(document.getElementById('hello'), 'scroll'); // 没问题
handleEvent(document.getElementById('world'), 'dbclick'); // 报错,event 不能为 'dbclick'
  1. 元组,数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象。
1
2
3
4
5
6
let xcatliu: [string, number];
xcatliu[0] = 'Xcat Liu';
xcatliu[1] = 25;

xcatliu[0].slice(1);
xcatliu[1].toFixed(2);

越界的元素,当赋值给越界的元素时,它类型会被限制为元组中每个类型的联合类型:

1
2
3
4
let xcatliu: [string, number];
xcatliu = ['Xcat Liu', 25];
xcatliu.push('http://xcatliu.com/');
xcatliu.push(true); // 报错,不能push boolean类型
  1. 枚举,关键词enum
  • 普通枚举

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

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

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

console.log(Days[0] === "Sun"); // true
console.log(Days[1] === "Mon"); // true
console.log(Days[2] === "Tue"); // true
console.log(Days[6] === "Sat"); // true
  • 常数枚举
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
const enum Directions {
Up,
Down,
Left,
Right
}

let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
```

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

- 外部枚举

5. 类

- 属性与方法

使用 class 定义类,使用 constructor 定义构造函数。

通过 new 生成新实例的时候,会自动调用构造函数。

``` typescript
class Animal {
constructor(name) {
this.name = name;
}
sayHi() {
return `My name is ${this.name}`;
}
}

let a = new Animal('Jack');
console.log(a.sayHi()); // My name is Jack
  • 继承

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

1
2
3
4
5
6
7
8
9
10
11
12
class Cat extends Animal {
constructor(name) {
super(name); // 调用父类的 constructor(name)
console.log(this.name);
}
sayHi() {
return 'Meow, ' + super.sayHi(); // 调用父类的 sayHi()
}
}

let c = new Cat('Tom'); // Tom
console.log(c.sayHi()); // Meow, My name is Tom
  • 存取器

使用 getter 和 setter 可以改变属性的赋值和读取行为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Animal {
constructor(name) {
this.name = name;
}
get name() {
return 'Jack';
}
set name(value) {
console.log('setter: ' + value);
}
}

let a = new Animal('Kitty'); // setter: Kitty
a.name = 'Tom'; // setter: Tom
console.log(a.name); // Jack
  • 静态方法

使用 static 修饰符修饰的方法称为静态方法,它们不需要实例化,而是直接通过类来调用:

1
2
3
4
5
6
7
8
9
class Animal {
static isAnimal(a) {
return a instanceof Animal;
}
}

let a = new Animal('Jack');
Animal.isAnimal(a); // true
a.isAnimal(a); // TypeError: a.isAnimal is not a function
  • public private 和 protected

  • 抽象类

abstract 用于定义抽象类和其中的抽象方法。

抽象类是不允许被实例化的;抽象类中的抽象方法必须被子类实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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');
  1. 类与接口
  • 类继承接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
interface Alarm {
alert();
}

class Door {
}

class SecurityDoor extends Door implements Alarm {
alert() {
console.log('SecurityDoor alert');
}
}

class Car implements Alarm {
alert() {
console.log('Car alert');
}
}
  • 类继承多个接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
interface Alarm {
alert();
}

interface Light {
lightOn();
lightOff();
}

class Car implements Alarm, Light {
alert() {
console.log('Car alert');
}
lightOn() {
console.log('Car light on');
}
lightOff() {
console.log('Car light off');
}
}
  • 接口继承接口
1
2
3
4
5
6
7
8
interface Alarm {
alert();
}

interface LightableAlarm extends Alarm {
lightOn();
lightOff();
}
  • 接口继承类
1
2
3
4
5
6
7
8
9
10
class Point {
x: number;
y: number;
}

interface Point3d extends Point {
z: number;
}

let point3d: Point3d = {x: 1, y: 2, z: 3};
  • 混合类型
1
2
3
4
5
6
7
8
interface SearchFunc {
(source: string, subString: string): boolean;
}

let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
return source.search(subString) !== -1;
}
  • namespace,之前叫module,内部使用export导出,引入的时候用全名或者import成别名