如何在TypeScript中正确设计API模块?

最后发布: 2018-02-27 16:42:41


问题

我想设计一个用于访问外部IS的TypeScript(2.7)模块,我们称之为InfoSys。 我使用以下方法。

我创建了info-sys.ts ,它定义了API类以及相关的接口和枚举,例如:

class Api {
    constructor(private endpoint: Endpoint) {
        // ...
    }
}

enum Endpoint {
    CONTACTS = "contacts"
}

interface Contact {
    name: string;
}

现在,我要以特定名称导出所有内容。 因此,我在导出语句后附加了:

export const InfoSys = {
    Api,
    Endpoint,
    Contact
};

当我尝试在另一个文件中使用该模块时,例如:

import { InfoSys } from "info-sys";

// this line throws error: "Cannot find namespace 'InfoSys'"
private api: InfoSys.Api;

// but this line is ok
api = new InfoSys.Api(InfoSys.Endpoint.CONTACTS);

起作用的方式如下-分别导出每个片段:

export class Api {
    constructor(private endpoint: Endpoint) {
        // ...
    }
}

export enum Endpoint {
    CONTACTS = "contacts"
}

export interface Contact {
    name: string;
}

并将它们全部导入一个变量:

import * as InfoSys from "info-sys";

但是变量的名称可以是任何名称。 这对功能不是很关键,但是我想强迫将使用info-sys模块的开发人员在访问它时使用特定名称(以简化可读性和可维护性)。 如何正确设计这样的模块?

node.js typescript node-modules
回答

您可以使用namespace

export namespace InfoSys {
  Api,
  Endpoint,
  Contact
};

通常,应避免这种方法。 但是对于您来说,这是很好的,因为您要交付紧密相关的内容。

如果Api是所有这些的唯一入口点,那么我也建议这样做:

export class InfoSysApi { ... }
export namespace InfoSysApi {
  export enum Endpoint = { ... }
  export interface Contact { ... }
}  

更新:为确保我明白这一点,请不要执行以下操作:

export namespace Foo {
  export function X() { return 'x' }
  export function Y() { return 'y' }
}

仅使用export namespace来导出“类型”,而不是值。

在TypeScript手册中: https : //www.typescriptlang.org/docs/handbook/declaration-merging.html

尽管该表说名称空间可以包含值,但是如果您正在编写ESM(导入/导出),则认为这是不好的做法。

命名空间和ESM是获得相似结果的两种不同机制。 不要将它们混合在一起。