angular - 从 Angular 项目中 TypeLITE 生成的多级命名空间导入 TypeScript 枚举

标签 angular typescript webpack typelite

在 Angular 项目中,我使用 TypeLITE 为来自后端的对象自动生成一堆接口(interface)。该部分运行良好,我对对象具有智能感知,并且(在某种程度上)对这些对象具有类型安全性。

但现在我遇到了第一个包含枚举的类,TypeLITE 正确地提取并在 enums.ts 中创建了 TypeScript 代码。这两个文件的内容如下所示:

classes.d.ts

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

枚举.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;

“classes.d.ts”中引用该枚举的实际接口(interface)仍然可以正常工作。

但现在我尝试导入该命名空间以在运行时访问“Status”枚举,但不知道该怎么做。无论我做什么,命名空间都不可用。

我尝试将其更改为“导出命名空间...”甚至“导出模块...”,但这会破坏“classes.d.ts”中生成的代码。我需要一个允许我在运行时使用枚举并保持与类的连接完好无损的解决方案。

我知道在模块和命名空间方面存在一些不兼容性,但我只是假设有某种方法可以绕过它并实际使用这些枚举?

USED VERSION
Angular 4.3.6
TypeScript 2.3.4.

编辑:简化示例

如果您想在自己的机器上尝试我遇到的问题,请按照以下步骤操作:

1) 创建一个新的最小 Angular 应用

ng new enumtest --minimal

2) 使用以下代码修改 app.component.ts 文件:

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) 添加这个文件 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;

预期行为:“1”将显示在页面上(枚举的值)并且它仍然可以编译,因为所有引用仍然完好无损(例如 My.Other.Multi.Level.Namespace.SomeInterface.Context 仍然连接到 My .Multi.Level.Namespace.MyInterface[]).

最佳答案

正如@Aleksey L. 提到的,您需要export 命名空间,它只适用于一个文件,但问题是每当您在顶层进行导出时,Typescript 开始假设file 是一个模块(并且有充分的理由)。

Typescript 的

Namespace 是为了模仿文件中的 module 行为而发明的,这些文件假定位于 global

你有几个选择:

  1. 如果你不需要全局的命名空间,你可以去掉它,直接从每个文件中导出枚举/接口(interface)。
  2. 如果你确实需要命名空间,它应该被导出,所有的内容都应该写在同一个文件中,所以枚举和接口(interface)将在同一个文件中

实际上,在我的工作中,我们曾经大量使用命名空间(当我们所有的代码库都在全局上声明时),然后每当我们在构建系统中引入 Webpack 时,我们就开始将我们的代码转换为使用 ES6 模块,其中一个步骤是删除命名空间。

我们需要逐步过渡,因此一些代码使用了 namespaces 和一些 ES6 模块。 为了保持向后兼容性,我们保留了包含命名空间的文件,并且为每个文件创建了一个新文件,该文件从全局读取命名空间并将其内部导出。

类似的东西:

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

   }
}

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

希望对您有所帮助。

关于angular - 从 Angular 项目中 TypeLITE 生成的多级命名空间导入 TypeScript 枚举,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46807148/

相关文章:

javascript - 使用 TypeScript 编写 Express.js 应用程序有哪些缺点?

angular - 访问子组件中的父内容或更好的方式

javascript - 部署 AngularJS 1.x - Webpack 应用程序到 Tomcat

angular - 无法为奇数行和偶数行设置单独的颜色

javascript - 如何使用 rxjs 以一定的时间间隔从一定范围内发出整数

typescript - Azure devops 失败 TS build : ' Type ' false' is not assignable to type 'Date' : but type is defined as 'Date | boolean' and build works locally

webpack - 将手写笔添加到具有 css 模块的 webpack 2 应用程序

javascript - 如何在代码执行过程中强制更新 View ?

javascript - 为什么 Swiper 在 Angular 上不适合我?

angular - 如何显示响应错误正文 Angular 4