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.
