Kuinka voin yhdistää TypeScriptin rajapintoja useiden tiedostojen välillä samassa nimialueessa


Yritän jäsentää hankalan konfiguraatiorajapinnan/objektin jakamalla sen eri osiot erillisiin tiedostoihin namespace-alueen alle, jonka olen ovelasti nimennyt Config.

Dokumentaatio käsittelee nimiavaruuksia, jotka kattavat useita tiedostoja, ja rajapintojen deklarointien yhdistämistä, mutta en tunnu saavan niitä toimimaan yhdessä.

src/config/index.ts

/// <reference path="./server.ts" />
import fs from 'fs';
import json5 from 'json5';

const _config = readConfig();

namespace Config {
    export const config = _config;

    export interface IConfig {
        someGeneralProperty: {
            // ...
        }
    }
}

function readConfig(): Config.IConfig {
    return json5.parse(fs.readFileSync('./path/to/config.json', 'utf-8'));
}

function doSomeOtherStuff() {
    // fails: Property 'server' does not exist on type 'IConfig'.
    console.log(_config.server.host);
}

src/config/server.ts

/// <reference path="./index.ts" />

namespace Config {
    export interface IConfig {
        server: {
            host: string;
            port: number;
        }
    }
}

src/index.ts

// fails: Module '"./config"' has no exported member 'config'.
import { config } from './config'; 

// fails: Cannot use namespace 'Config' as a value.
// fails: Namespace 'Config' has no exported member 'config'.
import config = Config.config;

Olen kokeillut useita erilaisia tapoja viedä asioita, kuten export default Config;, export namespace Config {...} jokaisessa src/config/... tiedostossa, muuttamalla export const config muotoon export var config. Tiedostossa src/config/index.ts kokeilin export * from './server'. Mikään ei näytä auttavan.

Minulla on tunne, että teen tämän ihan väärin.

Omituisesti, nimiavaruuden sisällä olevat rajapinnat jokaisessa tiedostossa viedään nimiavaruudesta, joten tiedostossa src/index.ts voin tehdä:

import IConfig = Config.IConfig;

let c: IConfig;
console.log(c.server.host);

mutta en voi tehdä sitä kummassakaan src/config/index.ts tai src/config/server.ts.

Vastaus #1

Aluksi sinun pitäisi päättää itse, haluatko määrittää config-objektin moduulin alueelle (eli import/export) vai globaaliin alueeseen (eli window selaimissa, global node:ssa).

Nimiavaruuksien päätarkoitus on määritellä ominaisuuksia/arvoja globaalissa laajuudessa. Kuten oikein huomautit linkkien avulla, yhtä nimettyjä nimiavaruuksia yhdistellään - siihen sisältyvät myös sisäiset jäsenet, kuten IConfig-rajapinta.

Tässä on juttu: Yhdistäminen tapahtuu vain, kun tiedosto, joka sisältää namespace, on skripti (ei-moduulitiedosto ilman import/export päätasolla).

Tiedostossa src/config/index.ts sinulla on import-lausekkeita, joten tiedostosta tulee moduuli ja namespace Config ei yhdisty. Sen sijaan se on pikemminkin moduulin sisäinen nimiavaruus, jota ei edes exportoida (katso Dokumentaatio: Turha nimiavaruus, Älä käytä nimiavaruuksia moduuleissa). Config-nimiavaruus tiedostossa src/config/server.ts muodostaa oman globaalin nimiavaruuden (ei-moduulitiedosto), sen takia voit silti käyttää siinä olevaa IConfig-tyyppiä.

Yhteenvetona, jos haluat, että konfiguraatio (arvo ja tyyppi) on globaali, varmista, että jokainen osa moniosaisesta nimialueesta on määritelty ei-moduulitiedostossa. Jos konfiguraatio halutaan viedä moduulista (suositeltava tapa, jos mahdollista!; parempi kapselointi, ei globaalin tilan saastumista, "moderni" tapa), jatka lukemista.

Vaihtoehto: vie määritys moduulissa

src/config/server.ts:

export interface ServerConfig {
  server: {
    host: string;
    port: number;
  }
}

// you could also read a server-specific config value here, export it
// and merge it with a separately read common config value in index.ts
// export serverConfig: ServerConfig = readServerConfig()

src/config/index.ts:

import { ServerConfig } from "./server"

interface CommonConfig {
  someGeneralProperty: {
    // ...
  }
}

export type IConfig = CommonConfig & ServerConfig

export const config: IConfig = readConfig(); // whatever readConfig looks like

src/index.ts:

import { config } from './config'; 

config.server;
config.someGeneralProperty

Vapaasti säädä tarvitsemasi osat.

Aiheeseen liittyviä artikkeleita