参考文献:

TypeScript 中文网

1. 基础类型

  • 布尔型:boolean

  • 数字:number

  • 字符串:string

  • 数组

    // 两种方式
    let list: number[] = [1, 2, 3];
    let list: Array<number> = [1, 2, 3];
    
  • 元组:元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。

    let x: [string, number];
    
  • 枚举

    enum Color {Red, Green, Blue}
    let c: Color = Color.Green;
    
    // 默认情况下,从0开始为元素编号。 你也可以手动的指定成员的数值。 
    enum Color {Red = 1, Green, Blue}
    let c: Color = Color.Green;
    
    let colorName: string = Color[2];
    console.log(colorName);  // 显示'Green'因为上面代码里它的值是2
    
  • Any:它允许你在编译时可选择地包含或移除类型检查。

  • Void:它表示没有任何类型。 当一个函数没有返回值时,你通常会见到其返回值类型是 void

  • Null 和 Undefined:默认情况下 null 和 undefined 是所有类型的子类型。 就是说你可以把 null 和 undefined 赋值给 number 类型的变量。

  • Never:表示的是那些永不存在的值的类型。

    • 例如, never 类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型; 变量也可能是 never类型,当它们被永不为真的类型保护所约束时。
    • never 类型是任何类型的子类型,也可以赋值给任何类型;然而,没有类型是 never 的子类型或可以赋值给 never 类型(除了 never 本身之外)。 即使 any 也不可以赋值给 never。
  • Object:object 表示非原始类型,也就是除 number,string,boolean,symbol,null 或 undefined 之外的类型。比如对象

  • 类型断言:通过类型断言这种方式可以告诉编译器,“相信我,我知道自己在干什么”。 类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构。

    // 两种方式
    let someValue: any = "this is a string";
    let strLength: number = (<string>someValue).length;
    
    let someValue: any = "this is a string";
    let strLength: number = (someValue as string).length;
    

2. 接口

2.1 接口初探

interface LabelledValue {
  label: string;
}

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

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

2.2 可选属性

interface SquareConfig {
  color?: string;
  width?: number;
}

2.3 只读属性

一些对象属性只能在对象刚刚创建的时候修改其值。 你可以在属性名前用 readonly 来指定只读属性

interface Point {
    readonly x: number;
    readonly y: number;
}

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

只读数组

TypeScript具有 ReadonlyArray<T> 类型,它与 Array<T> 相似,只是把所有可变方法去掉了,因此可以确保数组创建后再也不能被修改:

let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a;
ro[0] = 12; // error!
ro.push(5); // error!
ro.length = 100; // error!
a = ro; // error!

readonly vs const

最简单判断该用 readonly 还是 const 的方法是看要把它做为变量使用还是做为一个属性。 做为变量使用的话用 const,若做为属性则使用 readonly。

2.4 函数类型

接口能够描述 JavaScript 中对象拥有的各种各样的外形。 除了描述带有属性的普通对象外,接口也可以描述函数类型。

interface SearchFunc {
  (source: string, subString: string): boolean;
}

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

对于函数类型的类型检查来说,函数的参数名不需要与接口里定义的名字相匹配。 比如,我们使用下面的代码重写上面的例子:

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

如果你不想指定类型,TypeScript 的类型系统会推断出参数类型,因为函数直接赋值给了 SearchFunc 类型变量。

let mySearch: SearchFunc;
mySearch = function(src, sub) {
    let result = src.search(sub);
    return result > -1;
}

2.5 可索引类型

与使用接口描述函数类型差不多,我们也可以描述那些能够“通过索引得到”的类型,比如 a[10]ageMap["daniel"]。 可索引类型具有一个 索引签名,它描述了对象索引的类型,还有相应的索引返回值类型。 让我们看一个例子:

interface StringArray {
  [index: number]: string;
}

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

let myStr: string = myArray[0];

2.6 类类型

2.6.1 实现接口

interface ClockInterface {
    currentTime: Date;
}

class Clock implements ClockInterface {
    currentTime: Date;
    constructor(h: number, m: number) { }
}

2.7 继承接口

interface Shape {
    color: string;
}

interface Square extends Shape {
    sideLength: number;
}

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

3. 类

3.1 类

class Greeter {
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
    }
    greet() {
        return "Hello, " + this.greeting;
    }
}

let greeter = new Greeter("world");

3.2 继承

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();

3.3 公共,私有与受保护的修饰符

  • 默认 public
  • Privete :只能在类的内部访问
  • protected:可以在派生类中访问

3.4 存取器

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!");
        }
    }
}

3.5 静态属性

class Grid {
    static origin = {x: 0, y: 0};
    calculateDistanceFromOrigin(point: {x: number; y: number;}) {
        let xDist = (point.x - Grid.origin.x);
        let yDist = (point.y - Grid.origin.y);
        return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale;
    }
    constructor (public scale: number) { }
}

3.6 抽象类

抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化。 不同于接口,抽象类可以包含成员的实现细节。 abstract 关键字是用于定义抽象类和在抽象类内部定义抽象方法。

abstract class Animal {
    abstract makeSound(): void;
    move(): void {
        console.log('roaming the earch...');
    }
}

4. 函数

4.1 可选参数和默认参数

当有默认参数的时候,参数是可选的,并且类型和默认值是同一个类型

function buildName(firstName: string, lastName?: string) {
    // ...
}

function buildName(firstName: string, lastName = "Smith") {
    // ...
}

5. 泛型

5.1 了解泛型

// 传入什么,返回什么
function identity<T>(arg: T): T {
    return arg;
}

6. 高级类型

6.1 类型别名

type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;