TypeScript - 条件模块导入/导出

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13444064/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 02:46:51  来源:igfitidea点击:

TypeScript - conditional module import/export

typescript

提问by Oleg Mihailik

TypeScripts abstracts away module imports/exports in sort of 'declarative' manner.

TypeScripts 以某种“声明性”的方式抽象掉模块导入/导出。

But what if I want to import or export something based on some runtime-computed condition?

但是,如果我想根据某些运行时计算条件导入或导出某些内容怎么办?

The most common use case is sharing code between platforms like Node.js and Windows Script Host.

最常见的用例是在 Node.js 和 Windows Script Host 等平台之间共享代码。

TypeScript's very own io.ts that abstracts input/output in TSC compiler manually hacks around the built-in TypeScript's very own module syntax. Is that the only way?

TypeScript 自己的 io.ts 抽象了 TSC 编译器中的输入/输出,手动破解了内置的 TypeScript 自己的模块语法。这是唯一的方法吗?

P.S. The problem with just sticking import fs = module("fs")into ifstatement is that TypeScript only allows import statements at a top level. Which means in WSH require("fs")will be executed and obviously failing, as requireis undefined.

PS 仅将import fs = module("fs")粘贴到if语句中的问题是 TypeScript 只允许在顶层使用 import 语句。这意味着在 WSH 中require("fs")将被执行并且显然失败,因为require是未定义的。

采纳答案by JBaron

I agree that the fact that they can only have toplevel scope is suboptimal at best. Besides the issue you stated, it also means slower initial load times of software. For example within nodejs I now sometimes load a module in a function if that function is seldom used. So my application starts up quicker since it doesn't load that module yet.

我同意他们只能拥有顶级范围的事实充其量是次优的。除了您所说的问题之外,它还意味着软件的初始加载时间较慢。例如,在 nodejs 中,如果很少使用该函数,我现在有时会在该函数中加载一个模块。所以我的应用程序启动得更快,因为它还没有加载那个模块。

And of course you could use require or AMD directly, but than you will miss some of the typing benefits.

当然,您可以直接使用 require 或 AMD,但是您会错过一些打字的好处。

I think however that the real problem lies in the fact that harmony/es6 defined modules to be toplevel and TS seems to be following that proposal. So not sure how much TS team can do without deriving from the standards body.

然而,我认为真正的问题在于,harmony/es6 将模块定义为顶级,而 TS 似乎遵循该提议。因此,不确定 TS 团队可以在不源自标准机构的情况下做多少。

回答by Andrew Faulkner

I have a slightly clunky but very effective solution for this, particularly if you're using conditional import/export for unit testing.

我有一个稍微笨拙但非常有效的解决方案,特别是如果您使用条件导入/导出进行单元测试。

Have an export that is always emitted, but make the contents vary based on a runtime value. E.g.:

具有始终发出的导出,但使内容根据运行时值而变化。例如:

// outputModule.ts
export const priv = (process.env.BUILD_MODE === 'test')
  ? { hydrateRecords, fillBlanks, extractHeaders }
  : null

Then in the consuming file, import the export, check that the imported value exists, and if it does, assign all the values you'd otherwise import stand-alone to a set of variables:

然后在消费文件中,导入导出,检查导入的值是否存在,如果存在,则将您要单独导入的所有值分配给一组变量:

// importingModule.spec.ts
import { priv } from './outputModule';

const { hydrateRecords, fillBlanks, extractHeaders } = priv as any;
// these will exist if environment var BUILD_MODE==='test'

Limitations:

限制:

  1. You sadly have to set the import to 'any' to make the compiler happy.
  2. You need to check for whether or not specific imports are defined (but that comes with the territory).
  3. The importing file will expect the values to be defined. You will thus have to ensure importing files actually need the modules (which is fine if you're e.g. dealing with files only run during testing), or you'll have to define alternative values for cases where they don't actually get exported.
  1. 遗憾的是,您必须将导入设置为 'any' 以使编译器满意。
  2. 您需要检查是否定义了特定的导入(但随地域一起提供)。
  3. 导入文件将期望定义这些值。因此,您必须确保导入文件确实需要这些模块(这很好,例如,如果您要处理仅在测试期间运行的文件),或者您必须为实际上并未导出的情况定义替代值。

Still, it worked really well for me for my purposes, hopefully it works for you too. It's particularly useful for unit testing private methods.

尽管如此,就我的目的而言,它对我来说非常有效,希望它也适用于您。它对于单元测试私有方法特别有用。

回答by mPrinC

From TypeScript v2.4 you can use dynamic import to achieve conditional importing

从 TypeScript v2.4 开始,您可以使用动态导入来实现条件导入

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-4.html

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-4.html

An async example:

一个异步示例:

async function importModule(moduleName):Promise<any>{
    console.log("importing ", moduleName);
    const importedModule = await import(moduleName);
    console.log("\timported ...");
    return importedModule;
}

let moduleName:string = "module-a";
importModule(moduleName)
.then(importedModule => {
    console.log("importedModule");
});

回答by Fenton

There is a mechanism for dynamic imports in TypeScript, although the implementation differs based on the module kind.

TypeScript 中有一种动态导入机制,尽管实现因模块类型而异。

The example below (for AMD) will conditionally load the module:

下面的示例(对于 AMD)将有条件地加载模块:

declare function require(moduleNames: string[], onLoad: (...args: any[]) => void): void;

import * as ModuleAlias from './mod';

const someCondition = true;

if (someCondition) {
    require(["./mod"], (module: typeof ModuleAlias) => {
        console.log(module.go());
    });
}

The importstatement at the top of the file is inert, and the actual loading of the module will not happen unless the condition if (someCondition)is true.

import文件顶部的语句是惰性的,除非条件if (someCondition)为真,否则模块的实际加载不会发生。

You can test this by changing someConditionand seeing the impact on your network tab, or you can look at the generated code... in the dynamic version, "./mod"does not appear in the definecall. In the non dynamic one, it does.

您可以通过更改someCondition并查看对您的网络选项卡的影响来测试这一点,或者您可以查看生成的代码...在动态版本中,"./mod"不会出现在define调用中。在非动态的情况下,它确实如此。

With Dynamic Loading

动态加载

define(["require", "exports"], function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    const someCondition = true;
    if (someCondition) {
        require(["./mod"], (module) => {
            console.log(module.go());
        });
    }
});

Without Dynamic Loading

无动态加载

define(["require", "exports", "./mod"], function (require, exports, ModuleAlias) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    const someCondition = true;
    if (someCondition) {
        console.log(ModuleAlias.go());
    }
});