基本类型

Boolean

let isDone: boolean = false;

Number

let decimal: number = 6;

String

let color: string = 'blue';

let fullName: string = 'Bob Bobbington';
let sentence: string = `Hello, my name is ${fullName}.`

Array

let list: number[] = [1, 2, 3];

Enum

enum Color {Red, Green, Blue};
let c: Color = Color.Green;

enum Color {Red = 1, Green, Blue};
let colorName: string = Color[2];   // 'Green'

Any

let notSure: any = 4;
notSure = 'maybe a string instead';
notSure = false;

let list: any[] = [1, true, "free"];

对比:Object 类型可以任意赋值,但不能调用方法。

let notSure: any = 4;
notSure.ifItExists();
notSure.toFixed();

let prettySure: Object = 4;
prettySure.toFixed();   // Error: Property 'toFixed' doesn't exist on type 'Object'.

Void

function warnUser(): void {
  alert('This is my warning message');
}

Null and Undefined

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

默认情况下,null 和 undefined 是其他类型的子类型。也就是说,可以把 null 或 undefined 赋值给其他类型的变量。开启 --strictNullChecks 禁用上述规则。

Never

function error(message: string): never {
  throw new Error(message);
}

function fail() {
  return error('Something failed');
}

function infiniteLoop(): never {
  while (true) { }
}

Type assertions

类似于其他语言的「类型转换」,但仅仅起到告知编译器的作用,对代码执行本身没有任何影响。

let someValue: any = 'this is a string';
let strLength: number = (<string>someValue).length;

// JSX 环境下使用如下语法:
let someValue: any = 'this is a string';
let strLength: number = (someValue as string).length;

Interfaces

定义变量的「形状」。

interface LabelledValue {
  label: string;
}

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

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

使用未定义的属性会报错,防止拼写错误。如上述代码中拼错 label:labelledObj. lable,编译器会报错。

可省略的属性

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

function createSquare(config: SquareConfig): { color: string; area: number } {
  // ...
}

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

只读属性

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

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

只读数组:不允许对数组做任何操作,包括修改和增删元素。

let ro: ReadonlyArray<number> = a;

绕过类型检测的方式

Type assertion:

let mySquare = createSquare(<SquareConfig>{ width: 100, opacity: 0.5 });

或者定义允许其他任意属性:

interface SquareConfig {
  color?: string;
  width?: number;
  [propName: string]: any;
}

Function Types

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

let mySearch: SearchFunc;
mySearch = function(src, sub) {
  // ...
}

Indexable Types

index 支持 number 和 string 类型。

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

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

let myStr: string = myArray[0];

number 类型必须是 string 类型的子类型。

class Animal {
  name: string;
}
class Dog extends Animal {
  breed: string;
}

// Error: indexing with a 'string' will sometimes get you a Dog!
interface NotOkay {
  [x: number]: Animal;
  [x: string]: Dog;
}

只读:

interface ReadonlyStringArray {
  readonly [index: number]: string;
}

let myArray: ReadonlyStringArray = ['Alice', 'Bob'];
myArray[2] = 'Mallory'; // error!

Class Types

Interface 只能定义 class 的 public 属性和方法。

interface ClockInterface {
  currentTime: Date;
  setTime(d: Date);
}

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

Interface 的扩展

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;

混合类型

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;

Public、private 和 protected 修饰符

默认属性:public

private:无法外部调用。

class Animal {
  private name: string;
  constructor(theName: string) { this.name = theName; }
}

new Animal('Cat').name; // Error: 'name' is private;

protacted:继承类的实例可以调用,但无法外部调用。

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;
  }

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

let howard = new Employee('Howard', 'Sales');
console.log(howard.getElevatorPitch());
console.log(howard.name);   // error

只读属性

class Octopus {
  readonly name: string;
  constructor (theName: string) {
    this.name = theName;
  }
}

快速定义属性

给 constructor 的参数加上修饰符,省去属性定义。

class SomeClass {
   constructor(
     private a: string,
     protacted b: string,
     public c: string,
     readonly d: string
   ) { }
}

抽象类

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

抽象类中的抽象方法不需要具体实现,实现代码写在继承它的类里。

class Cat extends Animal {
  constructor(public name: string) { }
  makeSound(): void {
    console.log('meow');
  }
  move(): void {
    super();
    console.log('cat is moving...');
  }
}

函数

函数类型

function add(x: number, y: number): number {
  return x + y;
}

let myAdd = function(x: number, y: number): number { return x + y; };

可省略参数

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

let result1 = buildName('Bob');
let result3 = buildName('Bob', 'Adams'); 
let result2 = buildName('Bob', 'Adams', 'Sr.');  // error, too many parameters

默认参数

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

Rest 参数

function buildName(firstName: string, ...restOfName: string[]): string {
  return `${firstName} ${restOfName.join(' ')}`;
}

let employeeName = buildName('Joseph', 'Samuel', 'Lucas', 'MacKinzie');

重载

function pickCard(x: number[]): number;
function pickCard(x: number): Card;
function pickCard(x): any {
  if (typeof x == "object") {
    // ...
  } else if (typeof x == "number") {
    // ...
  }
}

注意:以上代码中的 function pickCard(x): any 并不是重载的定义。

Generics

T 表示用户在调用时指定的类型。

function identity<T>(arg: T): T {
  return arg;
}

let output = identity<string>('myString');

Generic Array

function loggingIdentity<T>(arg: T[]): T[] {
  console.log(arg.length);  // Array has a .length, so no more error
  return arg;
}

Generic Classes

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);  // Now we know it has a .length property, so no more error
  return arg;
}

指定泛型之间的依赖:

function copyFields<T extends U, U>(target: T, source: U): T {
  // ...
}

let x = { a: 1, b: 2, c: 3, d: 4 };

copyFields(x, { b: 10, d: 20 });
copyFields(x, { Q: 90 });   // error: property 'Q' isn't declared in 'x'.