函数类型

利用 interface 声明函数类型,只需要把接口定义中的属性写成函数签名即可。

像这样:

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

如果我们的函数本身还有一些属性,例如 Node.js 中的 require() 方法,我们既可以 require("package") 又可以 require.resolve("package")。这是需要首先为该方法定义一个接口,然后再通过 extends 它来添加属性。

interface NodeRequireFunction {
    (id: string): any;
}

interface NodeRequire extends NodeRequireFunction {
    resolve: RequireResolve;
    cache: any;
    extensions: NodeExtensions;
    main: NodeModule | undefined;
}

索引类型

有时我们想让我们对象支持向数组那样按照数字下标来存取数据,有时我们会想创建一个”字典”对象来存取任意的 “key/value” 对应关系。这两种情况就需要声明索引类型。区别在于索引本身的类型是数字还是字符串。

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

interface NameAddressMap {
    [index: string]: string;
}

我们可以把一个对象声明成既支持字符串索引有支持数字索引:

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

如果我们的对象要同时支持两种索引类型,那么必须保证字符串索引对应值的类型是数字索引对应值的类型的超集。

Why?因为在 JavaScript 的实现中,当我们以一个数字作为 key 访问对象属性时,JavaScript 会首先将该数字转变成字符串形式,再进行属性读取。

例如像下面这样是不可以的:

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

interface NotOkay {
    [x: number]: Animal;
    [x: string]: Dog;
}