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);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[];
}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;
}
// ...
}