Skip to content

Latest commit

 

History

History
271 lines (207 loc) · 5.66 KB

函数与类.md

File metadata and controls

271 lines (207 loc) · 5.66 KB

函数与类

函数

TypeScript 中函数的声明与 JavaScript 中保持一致,不过其允许指定额外的类型信息:

let stories: [string, string[]][] = [];

function addStory(title: string, tags: string[]): void {
  stories.push([title, tags]);
}

同样可以在 Lambda 表达式中指定类型:

let sortByLength: (x: string, y: string) => number = (x, y) =>
  x.length - y.length;
tags.sort(sortByLength);

也可以在函数参数中指定可选参数:

function storySummary(title: string, description?: string) {
  if (description) {
    return title + description;
  } else {
    return title;
  }
}

或者使用默认值:

function storySummary(title: string, description: string = '') {
  return title + description;
}

值得一提的是,当我们确定某个函数并不返回值时,需要注意不能使用 any 来替代 void,以避免误用返回值的情形:

function fn(x: () => void) {
  var k = x(); // oops! meant to do something else
  k.doSomething(); // error, but would be OK if the return type had been 'any'
}

JavaScript 中并不支持函数重载,但是在 TypeScript 中我们可以通过参数的不同实现重载:

declare function createStore(
  reducer: Reducer,
  preloadedState: PreloadedState,
  enhancer: Enhancer
);
declare function createStore(reducer: Reducer, enhancer: Enhancer);

Generator | 生成器

function* numbers(): IterableIterator<number> {
  console.log('Inside numbers; start');
  yield 1;
  console.log('Inside numbers; after the first yield');
  yield 2;
  console.log('Inside numbers; end');
}
// 迭代器结果的类型声明
interface IteratorResult<CompletedType, SuspendedType> {
  value: CompletedType | SuspendedType;
  done: this is { value: CompletedType };
}

类

从 ES6 开始,JavaScript 内建支持使用 class 关键字来声明类,而 TypeScript 允许我们以 implements 来实现某个接口,或者以 extends 关键字来继承某个类:

class Child extends Parent implements IChild, IOtherChild {
  // 类属性
  property: Type;

  // 类属性默认值
  defaultProperty: Type = 'default value';

  // 私有属性
  private _privateProperty: Type;

  // 静态属性
  static staticProperty: Type;

  // 构造函数
  constructor(arg1: Type) {
    super(arg1);
  }

  // 私有方法
  private _privateMethod(): Type {}

  methodProperty: (arg1: Type) => ReturnType;

  overloadedMethod(arg1: Type): ReturnType;

  overloadedMethod(arg1: OtherType): ReturnType;

  overloadedMethod(arg1: CommonT): CommonReturnT {}

  // 静态方法
  static staticMethod(): ReturnType {}

  subclassedMethod(arg1: Type): ReturnType {
    super.subclassedMethod(arg1);
  }
}

继承与实现

class TextStory implements Story {
  title: string;
  tags: string[];

  static storyWithNoTags(title: string): TextStory {
    return new TextStory(title, []);
  }

  constructor(title: string, ...tags) {
    this.title = title;
    this.tags = tags;
  }

  summary() {
    return `TextStory ${this.title}`;
  }
}

// 使用静态方法创建类对象
let story = TextStory.storyWithNoTags('Learning TypeScript');

class TutorialStory extends TextStory {
  constructor(title: string, ...tags) {
    // 调用父类构造函数
    super(title, tags);
  }

  // 复写父类的方法
  summary() {
    return `TutorialStory: ${this.title}`;
  }
}

现在 TypeScript 允许我们同时实现多个由 type 或者 interface 声明的类型,并且能够利用交叉操作:

class Point {
  x: number;
  y: number;
}

interface Shape {
  area(): number;
}

type Perimeter = {
  perimiter(): number;
};

type RectangleShape = Shape & Perimeter & Point;

class Rectangle implements RectangleShape {}

// 等价于
class Rectangle implements Shape, Perimeter, Point {}

抽象类

TypeScript 中我们同样可以定义抽象类(Abstract class),即包含抽象方法的类;抽象类不能够被直接初始化,需要通过子类继承并且实现抽象方法。

abstract class StoryProcessorTemplate {
  public process(url: string): Story {
    var title: string = this.extractTitle(url);
    var text: string = this.extractText(url);
    var tags: string[] = this.extractTags(text);
    return {
      title: title,
      tags: tags
    };
  }

  abstract extractTitle(url: string): string;

  abstract extractText(url: string): string;

  abstract extractTags(url: string): string[];
}

Decorator | 装饰器

TypeScript 内建支持装饰器语法,需要我们在编译配置中开启装饰器参数:

{
  "compilerOptions": {
    // ...
    "experimentalDecorators": true
  }
  // ...
}

装饰器提供了声明式的语法来修改类的结构或者属性声明,以简单的日志装饰器为例:

export function Log() {
  return function(
    target: Object,
    propertyKey: string,
    descriptor: TypedPropertyDescriptor<any>
  ) {
    // 保留原函数引用
    let originalFunction = descriptor.value || descriptor.get;

    // 定义包裹函数
    function wrapper() {
      let startedAt = +new Date();
      let returnValue = originalFunction.apply(this);
      let endedAt = +new Date();
      console.log(
        `${propertyKey} executed in ${endedAt - startedAt} milliseconds`
      );
      return returnValue;
    }

    // 将描述对象中的函数引用指向包裹函数
    if (descriptor.value) descriptor.value = wrapper;
    else if (descriptor.get) descriptor.get = wrapper;
  };
}

其使用方式如下:

import { Log } from './log';

export class Entity {
  // ...

  @Log()
  get title(): string {
    Entity.wait(1572);
    return this._title;
  }

  // ...
}