TypeScript 基础用法

基础类型

布尔值

1
let flag: boolean = false;

数字

注:支持十进制、十六进制、ECMAScript 2015 中引入的二进制和八进制

1
let num: number = 6;

字符串

1
let name: string = "bob";

symbol

注:symbol 类型的值是通过 Symbol 构造函数创建的,Symbols 是不可改变且唯一的。

1
2
let sym1 = Symbol();
let sym2 = Symbol("key"); // 可选的字符串 key

数组

1
2
3
let list: number[] = [1, 2, 3]; // number 代表数组中每个元素的类型

let newList: Array<number> = [1, 2, 3]; // 泛型,同上

元组

注:元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同

1
let x: [string, number] = ["hello", 10];

枚举

注:元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
enum Color {
Red,
Green,
Blue
}
let c: Color = Color.Green;
console.log(Color); // Green

enum newColor {
Red = 1,
Green = 2,
Blue = 4
}
let c: newColor = newColor[2];
console.log(newColor); // Green

Any

注:代表任意类型,它会跳过编译类型检查,新手往往会把 TypeScript 强行写成 AnyScript

1
2
let anyThing: any = 4;
let newAnyThing: any = false;

Void

注:与 any 相反,代表没有任何类型

1
2
3
4
5
6
function warnUser(): void {
// 代表没有返回值
console.log("This is my warning message");
}

let unusable: void = undefined; // 声明是只能赋值为 undefined 和 null

Null 和 Undefined

注:默认情况下 null 和 undefined 是所有类型的子类型。 就是说你可以把 null 和 undefined 赋值给 number 类型的变量。
你指定了–strictNullChecks 标记,null 和 undefined 只能赋值给 void 和它们各自。

1
2
let u: undefined = undefined;
let n: null = null;

Never

注:表示那些永不存在的值的类型。never 类型是任何类型的子类型,也可以赋值给任何类型

1
2
3
4
function error(message: string): never {
// 返回 never 的函数必须存在无法达到的终点
throw new Error(message);
}

Object

注:表示非原始类型,也就是除 number,string,boolean,symbol,null 或 undefined 之外的类型。

1
2
declare function create(o: object | null): void;
create({ prop: 0 });

泛型

注:把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊的类型。

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
35
36
37
function identity<T>(arg: T): T {
// 返回值的类型与传入参数的类型相同
return arg;
}

function loggingIdentity<T>(arg: T[]): T[] {
// 泛型类型
console.log(arg.length);
return arg;
}

class GenericNumber<T> {
// 泛型类
zeroValue: T;
add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function (x, y) {
return x + y;
};

interface Lengthwise {
length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
// 泛型约束
console.log(arg.length);
return arg;
}

function create<T>(c: { new (): T }): T {
// 类类型
return new c();
}

类型断言

注:以预期的类型编译,相当于类型转换。
在 TypeScript 里使用 JSX 时,只有 as 语法断言是被允许的。

1
2
3
4
5
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;

let newSomeValue: any = "this is a string";
let newStrLength: number = (someValue as string).length; // as 等价于前边的泛型

类的实质是一种引用数据类型,类的实例称为对象。

基础类

注:constructor 定义构造函数, 这个函数会在 new 创建类实例的时候被调用。

1
2
3
4
5
6
7
8
9
10
11
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}

let greeter = new Greeter("world");

继承

注:继承的关键字 extends。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Animal {
move(distanceInMeters: number = 0) {
console.log(`Animal moved ${distanceInMeters}m.`);
}
}

class Dog extends Animal {
bark() {
console.log("Woof! Woof!");
}
}

const dog = new Dog();
dog.bark();
dog.move(10);
dog.bark();

修饰符

注:public(默认),代表公有的,可以自由访问。
private 代表私有的,只能在类的内部访问。
protected 与 private 相似,但可以在派生类中访问。
readonly 只读属性必须在声明时或构造函数里被初始化。
static 静态属性,存在于类的本身,而不是实例化。

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
35
class Animal {
private name: string;
protected age: number;
readonly sex: string;
static type = "big";
public constructor(theName: string) {
this.name = theName;
}
public move(distanceInMeters: number) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}

class Person {
protected name: string;
constructor(name: string) {
this.name = name;
}
}

class Employee extends Person {
private department: string;

constructor(name: string, department: string) {
super(name);
this.department = department;
}

public getElevatorPitch() {
return `Hello, my name is ${this.name} and I work in ${this.department}.`;
}
}

let howard = new Employee("Howard", "Sales");
console.log(howard.getElevatorPitch());

参数属性

注:在参数中定义并初始化一个成员。

1
2
3
4
class Octopus {
readonly numberOfLegs: number = 8;
constructor(readonly name: string) {}
}

存取器

注:通过 getters/setters 来截取对对象成员的访问。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
let passcode = "secret passcode";

class Employee {
private _fullName: string;

get fullName(): string {
return this._fullName;
}

set fullName(newName: string) {
if (passcode && passcode == "secret passcode") {
this._fullName = newName;
} else {
console.log("Error: Unauthorized update of employee!");
}
}
}

let employee = new Employee();
employee.fullName = "Bob Smith";
if (employee.fullName) {
alert(employee.fullName);
}

抽象类

注:抽象类做为其它派生类的基类使用,abstract 关键字是用于定义抽象类和在抽象类内部定义抽象方法。

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
abstract class Department {
constructor(public name: string) {}

printName(): void {
console.log("Department name: " + this.name);
}

abstract printMeeting(): void; // 必须在派生类中实现
}

class AccountingDepartment extends Department {
constructor() {
super("Accounting and Auditing"); // 在派生类的构造函数中必须调用 super()
}

printMeeting(): void {
console.log("The Accounting Department meets each Monday at 10am.");
}

generateReports(): void {
console.log("Generating accounting reports...");
}
}

let department: Department; // 允许创建一个对抽象类型的引用
department = new Department(); // 错误: 不能创建一个抽象类的实例
department = new AccountingDepartment(); // 允许对一个抽象子类进行实例化和赋值
department.printName();
department.printMeeting();
department.generateReports(); // 错误: 方法在声明的抽象类中不存在

接口

接口的作用就是为例规范 Object 的类型

普通接口

1
2
3
4
5
6
7
8
9
10
interface LabelledValue {
label: string;
}

function printLabel(labelledObj: LabelledValue) {
console.log(labelledObj.label);
}

let myObj = { size: 10, label: "Size 10 Object" };
printLabel(myObj);

可选属性

注:带有可选属性的接口与普通的接口定义差不多,只是在可选属性名字定义的后面加一个?符号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
interface SquareConfig {
color?: string;
width?: number;
}

function createSquare(config: SquareConfig): { color: string; area: number } {
let newSquare = { color: "white", area: 100 };
if (config.color) {
newSquare.color = config.color;
}
if (config.width) {
newSquare.area = config.width * config.width;
}
return newSquare;
}

let mySquare = createSquare({ color: "black" });

只读属性

注:只在创建的时候可以赋值

1
2
3
4
5
6
7
interface Point {
readonly x: number;
readonly y: number;
}

let p: Point = { x: 10, y: 20 };
p.x = 5; // error!

ReadonlyArray

注:把所有可变方法去掉,确保数组创建后再也不能被修改。

1
2
3
let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a;
ro[0] = 12; // error!

额外的属性检查

注:避免可选属性接口中额外的属性导致的错误。

1
2
3
4
5
6
7
8
interface SquareConfig {
color?: string;
width?: number;
[propName: string]: any;
}

let squareOptions = { colour: "red", width: 100 };
let mySquare = createSquare(squareOptions);

函数类型

注:规范函数的参数列表和返回值。

1
2
3
4
5
6
7
8
9
interface SearchFunc {
(source: string, subString: string): boolean;
}

let mySearch: SearchFunc;
mySearch = function (source: string, subString: string) {
let result = source.search(subString);
return result > -1;
};

可索引的类型

注:规范通过索引得到的类型。

1
2
3
4
5
6
7
8
interface StringArray {
[index: number]: string;
}

let myArray: StringArray;
myArray = ["Bob", "Fred"];

let myStr: string = myArray[0];

类类型

注:规范类的类型。实现类型的关键字 implements。

1
2
3
4
5
6
7
8
9
10
11
12
interface ClockInterface {
currentTime: Date;
setTime(d: Date);
}

class Clock implements ClockInterface {
currentTime: Date;
setTime(d: Date) {
this.currentTime = d;
}
constructor(h: number, m: number) {}
}

继承接口

注:一个接口可以继承多个接口,创建出多个接口的合成接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
interface Shape {
color: string;
}

interface PenStroke {
penWidth: number;
}

interface Square extends Shape, PenStroke {
sideLength: number;
}

let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;

混合类型

注:一个对象可以同时做为函数和对象使用,并带有额外的属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
interface Counter {
(start: number): string;
interval: number;
reset(): void;
}

function getCounter(): Counter {
let counter = <Counter>function (start: number) {};
counter.interval = 123;
counter.reset = function () {};
return counter;
}

let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;

接口继承类

注:当接口继承了一个类类型时,它会继承类的成员但不包括其实现,接口同样会继承到类的 private 和 protected 成员。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Control {
private state: any;
}

interface SelectableControl extends Control {
select(): void;
}

class Button extends Control implements SelectableControl {
select() {}
}

class TextBox extends Control {
select() {}
}

// 错误:“Image”类型缺少“state”属性。
class Image implements SelectableControl {
select() {}
}