Importer TypeScript-enum fra flertrinns navnerom generert av TypeLITE i Angular-prosjekt


I et Angular-prosjekt bruker jeg TypeLITE for å automatisk generere en rekke grensesnitt for objekter som kommer fra backend. Den delen fungerer bra, og jeg har intellisense for objekter og (til en viss grad) typesikkerhet for dem.

Men nå kom jeg over den første klassen som inneholder en enum, som TypeLITE korrekt fanger opp og lager TypeScript-koden i enums.ts. Innholdet i de to filene ser slik ut:

klasser.d.ts

declare namespace My.Multi.Level.Namespace {
  interface MyInterface {
    Status: My.Multi.Level.Namespace.Status;
  }
}

enums.ts

namespace My.Multi.Level.Namespace {
  export const enum Status {
    Undefined = 0,
    New = 1,
    ...
  } 
}

someOtherFile.ts

// How/what to import to access this?
const status = My.Multi.Level.Namespace.New;

Og det faktiske grensesnittet i "classes.d.ts" som refererer til den enumen, fungerer fortsatt fint.

Men nå prøver jeg å importere det navnerommet for å få tilgang til "Status"-enumet under kjøring og kan ikke finne ut hvordan jeg skal gjøre det. Navnerommet er bare ikke tilgjengelig, uansett hva jeg gjør.

Jeg prøvde å endre det til "export namespace..." eller til og med "export module ...", men det ville ødelagt koden som genereres i "classes.d.ts". Jeg trenger en løsning som lar meg bruke enumen i kjøretid, samtidig som forbindelsen til klassene forblir intakt.

Jeg forstår at det er noen inkompatibilitet når det gjelder moduler og navneområder, men jeg antar bare at det finnes en måte å omgå det på og faktisk bruke de enumene?

USED VERSION
Angular 4.3.6
TypeScript 2.3.4.

REDIGER: Forenklet eksempel

Hvis du ønsker å prøve problemet jeg har på din egen maskin, vennligst følg disse trinnene:

1) Lag en ny minimal Angular-app

ng new enumtest --minimal

2) Endre app.component.ts-filen med denne koden:

import { Component, OnInit } from '@angular/core';
import { My } from './classes';

@Component({
  selector: 'app-root',
  template: `<p>{{myEnum}}</p>`
})
export class AppComponent implements OnInit {

  myEnum: My.Multi.Level.Namespace.Status;

  ngOnInit() {
    console.log("ngOnInit:begin:myEnum");
    this.myEnum = My.Multi.Level.Namespace.Status.New;
    console.log("ngOnInit:after:myEnum");
  }

}

3) Legg til denne filen classes.ts

// classes part

namespace My.Multi.Level.Namespace {
  export interface MyInterface {
    Title: string;
    Status: My.Multi.Level.Namespace.Status;
  }
}
namespace My.Other.Multi.Level.Namespace {
  export interface SomeInterface {
    Context: My.Multi.Level.Namespace.MyInterface[];
  }
}

// enums part

namespace My.Multi.Level.Namespace {
  export const enum Status {
      Undefined = 0,
      New  = 1
  } 
}

export import My = My;

Forventet oppførsel: "1" vil bli vist på siden (verdien til enumen) og det kompilerer fortsatt siden alle referanser fortsatt er intakte (som My.Other.Multi.Level.Namespace.SomeInterface.Context fortsatt tilkoblet til My.Multi.Level.Namespace.MyInterface[]).

Svar #1

Som @Aleksey L. nevnte, trenger du å export navneområdet, det vil fungere for én fil, men problemet er at når du har en eksport på toppnivå, begynner Typescript å anta at filen er et modul (og det er med god grunn).

Namespace i Typescript ble oppfunnet for å etterligne module-atferd i filer som antas å være på global.

Du har få alternativer:

  1. Hvis du ikke trenger navneområdet globalt, kan du kvitte deg med det, og eksportere enumen/grensesnittet direkte fra hver fil.
  2. Hvis du trenger navnerommet, bør det eksporteres, og alt innholdet bør skrives i samme fil, så enum og grensesnittet vil være i samme fil

Faktisk, på jobben min brukte vi en gang namespaces mye (da hele kodebasen vår var deklarert globalt), så når vi introduserte Webpack i byggesystemet vårt, begynte vi å konvertere koden vår til å bruke ES6-moduler, ett av trinnene var å fjerne namespaces.

Vi hadde et krav om å gjøre overgangen gradvis, så noe av koden brukte namespaces og noe ES6 modules. For å opprettholde bakoverkompatibilitet, beholdt vi filene som inneholdt navnrommene, og for hver fil opprettet vi en ny fil som leser navnrommet fra globalt og eksporterer det internt.

Noe sånt:

// old-file.ts
namespace someName {
   export class SomeClass {

   }
}

//old-file.es6.ts
export import SomeClass = someName.SomeClass;

Håper det hjelper.

Relaterte artikler