Búsqueda de sitios web

node.js - ¿Cómo diseñar correctamente un módulo API en TypeScript?


Quiero diseñar un módulo de TypeScript (2.7) para acceder a sistemas externos de información, llamémoslo InfoSys. Usé el siguiente enfoque.

Creé info-sys.ts que define una clase API y las interfaces y enumeraciones relacionadas, como:

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

enum Endpoint {
    CONTACTS = "contacts"
}

interface Contact {
    name: string;
}

Ahora quiero exportar todas las cosas bajo un nombre específico. Así que añadí la declaración de exportación:

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

Cuando intento usar el módulo en otro archivo, como:

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

La forma en que funciona es la siguiente: exportar cada pieza individualmente:

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

export enum Endpoint {
    CONTACTS = "contacts"
}

export interface Contact {
    name: string;
}

e impórtalos todos a una sola variable:

import * as InfoSys from "info-sys";

Pero el nombre de la variable puede ser cualquiera. No es crítico para la funcionalidad, pero quiero obligar a los desarrolladores, que usarán el módulo info-sys, a usar un nombre específico al acceder a él (para una mayor legibilidad y mantenibilidad). ¿Cómo diseñar correctamente dicho módulo?

Respuesta #1

Puedes usar namespace:

export namespace InfoSys {
  Api,
  Endpoint,
  Contact
};

En general, este enfoque debe evitarse. Pero en tu caso, está bien ya que estás entregando cosas que están estrechamente relacionadas.

Si Api es el único punto de entrada a todo esto, también recomendaría lo siguiente:

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

ACTUALIZACIÓN: Para asegurarme de que quede claro, NO hagas lo siguiente:

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

Solo usa export namespace para exportar "tipos enganchados", no valores.

En el manual de TypeScript: https://www.typescriptlang.org/docs/handbook/declaration-merging.html

Aunque la tabla dice que el namespace puede contener valores, se considera una mala práctica si estás escribiendo ESM (import/export).

Namespace y ESM son dos mecanismos diferentes para lograr un resultado similar. No los mezcles juntos.