【问题标题】:How do you expose class in a module to the global namespace in TypeScript?如何将模块中的类暴露给 TypeScript 的全局命名空间?
【发布时间】:2020-03-18 21:05:40
【问题描述】:

问题

给定

  • 我有一个包含模块和全局脚本(常规非模块脚本)的现有应用程序。
    • 模块
      • App.ts
    • 全局脚本
      • alpha.ts 包含一个名为 alpha 的类
      • beta.ts 包含一个名为 beta 的类
      • gamma.ts 包含一个名为 gamma 的类
  • 我想将全局脚本 (gamma.ts) 中的一个类转换为模块
    • 通过在 gamma.ts 中的 class gamma {} 之前添加 export default
  • 我想将gamma 类导入全局命名空间(即窗口对象),以便现有的全局和模块脚本可以访问它。

我尝试过的

我在 global.d.ts

周围尝试了很多东西

例如

import gammaAlias from "../scripts/gamma";
export as namespace NS_Global;

declare global {
    var qqq: {n:string};
    namespace ZZZ {
       export var gamma: gammaAlias;
    }
    var gamma: gammaAlias;
}

但没有一个有效

即TypeScript 告诉我以下之一

  • 伽玛不存在
  • Cannot use 'new' with an expression whose type lacks a call or construct signature.

github

我设置了一个 github 存储库来调查这些问题。 https://github.com/penguin020/expose-typescript-modules-globally

ConvertToModulesPOC_original 是工作“之前”的情况。

ConvertToModulesPOC 是将 gamma .ts 转换为 模块并在全球范围内公开它。

PS

问题仍然存在,如何将模块暴露给全局命名空间?

特别感谢任何使用 github 中示例的答案!

【问题讨论】:

  • 我认为declare global 只是一个类型声明,它实际上并没有做任何事情。您实际上需要将 window.gamma = gammaAlias 分配给 create 全局变量。
  • module compiler option 设置为无或系统应该可以工作。虽然它似乎没有很好地记录,但也许你会通过发出 ES6 模块,然后将它们与 rollup 或 webpack 正确捆绑在一起,这两者都可以选择将各种导出作为全局变量公开。
  • 修复了 alpha 问题
  • @Bergi - 我被限制使用 angular cli 进行生产,使用普通 system.js 进行开发。
  • 你是说你甚至不能使用tsconfig file?如果您可以共享更多配置可能会有所帮助,例如如何调用 angular cli 以及如何使用 system.js。

标签: typescript es6-modules


【解决方案1】:

我在“TypeScript: exposing module types in the global context and why to avoid it”中找到了答案;

我已经更新了 github repo。

我发现最显着的变化是:


tsconfig 中:

"module": "system",

yMod.ts

import gammaAlias from "../scripts/gamma.js";

declare global {
    export type gamma = gammaAlias;
    export const gamma: typeof gammaAlias;
}

(window as any).gamma = gammaAlias;

注意:您可以将全局环境声明放在另一个文件中,甚至是 *.d.ts 文件。


link above 分解了在全球范围内为每个符号提供三个引用的原因。该页面上已经很好地解释了,所以我只在这里总结一下:

  1. 向 TypeScript 编译器公开类 type(不生成代码)
  2. 将类 object 公开给 TypeScript 编译器(因此有一个对象可以调用 new;没有生成代码)
  3. 扩展窗口对象以在全局命名空间中公开类(生成代码)。

【讨论】:

  • 如果有人能找到更好的方法来做到这一点,我很乐意奖励赏金。
  • 出于好奇,您认为您的解决方案有哪些不足/不好的地方?据我所知,这种方法是惯用的做法。免责声明:我只阅读了代码,没有尝试编译或运行它
  • 可能类似于“导出为命名空间”,不会生成不必要的命名空间。我必须引用我想在全球公开的每个模块 3 次,这似乎......挥霍。
  • 在这 3 个操作中,有两个在类型级别(export typeexport const),指的是 TypeScript 中的两个不同的东西(分别是类型和值)。最后一个操作是需要执行的实际代码操作才能使类型级操作起作用。所以看到你用三个操作做三件事,我认为它不会变得更好。
【解决方案2】:

希望我正确理解了您的问题。您想将 'gamma' 公开给全局命名空间,以便您可以直接从 'window' 调用 'gamma.log()' 或从控制台?

将以下两行添加到类底部的 gamma.ts 中。

let g = new gamma();
(window as any).gamma = g

1) 第一行将一个新的 Gamma 类初始化为变量 g

2) 第二行将 g 导出到全局命名空间中,以便可以从 'window.g' 或只是 'g em>'。

Screenshot

拉取请求 #1:https://github.com/penguin020/expose-typescript-modules-globally/pull/1/files


我还建议将这两行代码移到您的主初始化文件“app.js”中。

伽玛.ts

export default class gamma {

app.ts

import gamma from "./gamma";
let g = new gamma();
(window as any).gamma = g

拉取请求#2:https://github.com/penguin020/expose-typescript-modules-globally/pull/2

【讨论】:

  • 不完全是我想要的,因为我希望类 gamma,而不是类的对象实例全局公开。为尝试 +1。
  • 这更容易,因为它已经暴露给全局命名空间。只需将 gamma.js 转换为第一个导入的脚本。然后在 alpha 或 beta 或您的控制台中调用“(new gamma()).log()”。 github.com/penguin020/expose-typescript-modules-globally/pull/1/…
【解决方案3】:

这对我有用。我只希望我不必重命名界面。

declare global {
  interface IMyClass extends MyClass { }
}

class MyClass {

}

declare global {
  type IMyClass = MyClass;
}

class MyClass {

}

【讨论】:

  • 问题是只有类型被导出到全局命名空间而不是实现。因此,你不能这样做new IMyClass()
  • 同名导出,发现TypeScript接受declare global { type MyClass = typeof MyClass; }。可悲的是,它似乎没有在新声明的 global-namespace-class 中找到原始类的所有符号。不知道为什么
猜你喜欢
  • 2018-10-31
  • 2016-02-25
  • 2019-06-25
  • 1970-01-01
  • 2021-05-18
  • 2021-09-18
  • 2020-05-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多