TypeScripts以“声明”的方式抽象出模块导入/导出。
但是如果我想根据某些运行时计算条件导入或导出某些内容呢?
最常见的用例是在Node.js和Windows Script Host等平台之间共享代码。
TypeScript自己的io.ts在TSC编译器中抽象输入/输出,手动破解内置的TypeScript自己的模块语法。这是唯一的方法吗?
P.S。将导入fs = module(“fs”)固定到 if 语句中的问题是TypeScript只允许顶级导入语句。这意味着WSH require(“fs”)将被执行并且明显失败,因为 require 未定义。
答案 0 :(得分:8)
我同意他们只能达到范围的事实在最好情况下并不是最理想的。除了你说的问题,它还意味着软件的初始加载时间较慢。例如,在nodejs中,如果很少使用该函数,我现在有时会在函数中加载模块。所以我的应用程序启动得更快,因为它还没有加载该模块。
当然你可以直接使用require或AMD,但是你会错过一些输入的好处。
然而,我认为真正的问题在于和谐/ es6定义的模块是顶层的,而TS似乎遵循该提议。所以不确定TS团队在没有得到标准组织的情况下可以做多少。
答案 1 :(得分:8)
我有一个稍微笨重但非常有效的解决方案,特别是如果您使用条件导入/导出进行单元测试。
具有始终发出的导出,但使内容根据运行时值而变化。 E.g:
// outputModule.ts
export const priv = (process.env.BUILD_MODE === 'test')
? { hydrateRecords, fillBlanks, extractHeaders }
: null
然后在使用文件中,导入导出,检查导入的值是否存在,如果存在,则将您以其他方式单独导入的所有值分配给一组变量:
// importingModule.spec.ts
import { priv } from './outputModule';
const { hydrateRecords, fillBlanks, extractHeaders } = priv as any;
// these will exist if environment var BUILD_MODE==='test'
限制:
尽管如此,它对我来说非常适合我的目的,希望它对你也有用。它对于私有方法的单元测试特别有用。
答案 2 :(得分:2)
在TypeScript中有一种动态导入机制,尽管实现因模块类型而异。
以下示例(针对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());
});
}
文件顶部的import
语句是惰性的,除非条件if (someCondition)
为真,否则不会发生模块的实际加载。
您可以通过更改someCondition
并查看对网络标签的影响进行测试,或者您可以查看生成的代码...在动态版本中,"./mod"
未显示在{ {1}}致电。在非动态的,它确实。
define
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());
});
}
});
答案 3 :(得分:2)
从TypeScript v2.4开始,您可以使用动态导入来实现条件导入
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-4.html
答案 4 :(得分:0)
找不到将条件导出作为条件导入的直接方法。但 我发现 Andrew Faulkner 的回答很有用,但我对这些限制不满意。
<块引用>我想出了一个解决上述限制的方法。这是我的步骤。
这是示例。
//CryptoUtil.ts
function encryptData(data : Buffer, key : Buffer) : Buffer {
// My encryption mechanism.
// I return a Buffer here.
}
function decryptData(data : Buffer, key : Buffer) : Buffer {
// My decryption mechanism.
// I return a Buffer here.
}
// Step 1
// Exporting things conditionally
export const _private = (process.env.NODE_ENV === "test") ? {
__encryptData : encryptData,
__decryptData : decryptData,
} : null;
请注意我如何将 encryptData
导出为 __encryptData
而不是直接导出为 encryptData
。我这样做只是因为我可以认为 __encryptData
在导入器模块中解构时是一个私有函数。这完全是我的喜好。
然后在导入东西时...
// CryptoUtil.test.ts
// Step 2
// import the exported object.
import { _private } from "./CryptoUtil";
// Step 3. De-structuring.
const {
__encryptData,
__decryptData,
} = _private as any;
// Step 4. Define new constants giving proper type.
const _encryptData : (data : string, password : Buffer) => Buffer = __encryptData;
const _decryptData : (encryptedData : Buffer, password : Buffer) => Buffer = __decryptData;
// Now I can use _encryptData, _decryptData having the proper type.
即使我提出这种方式来解决安德鲁的第一个限制,但我的方法引入了一个新的限制。也就是说,您必须在两个地方定义类型。当您更改导出函数的类型时,它不会神奇地更改导入函数的类型。您必须手动更改它。
答案 5 :(得分:0)
dvc run
灵感来自Andrew answer。