35

TypeScripts は、モジュールのインポート/エクスポートを「宣言型」の方法で抽象化します。

しかし、実行時に計算された条件に基づいて何かをインポートまたはエクスポートしたい場合はどうすればよいでしょうか?

最も一般的なユース ケースは、Node.js や Windows Script Host などのプラットフォーム間でコードを共有することです。

TSC コンパイラで入力/出力を抽象化する TypeScript 独自の io.ts は、組み込みの TypeScript 独自のモジュール構文を手動でハックします。それが唯一の方法ですか?

PS import fs = module("fs")ifステートメントに貼り付けるだけの問題は、TypeScript が最上位の import ステートメントのみを許可することです。これは、WSH でrequire("fs")が実行され、requireが定義されていないため、明らかに失敗することを意味します。

4

6 に答える 6

19

特に単体テストに条件付きインポート/エクスポートを使用している場合は、少し不格好ですが非常に効果的な解決策があります。

常に発行されるエクスポートがありますが、ランタイム値に基づいて内容が変化します。例えば:

// 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'

制限:

  1. 悲しいことに、コンパイラを満足させるには、インポートを「any」に設定する必要があります。
  2. 特定のインポートが定義されているかどうかを確認する必要があります (ただし、これには地域が付属しています)。
  3. インポートするファイルは、値が定義されていることを期待します。したがって、インポートするファイルが実際にモジュールを必要とすることを確認する必要があります (たとえば、テスト中にのみ実行されるファイルを扱う場合はこれで問題ありません)。または、実際にはエクスポートされない場合に備えて、代替値を定義する必要があります。

それでも、それは私の目的のためには本当にうまくいきました。これは、プライベート メソッドの単体テストに特に役立ちます。

于 2016-09-12T18:25:45.187 に答える
10

私は、彼らがトップレベルのスコープしか持てないという事実は、せいぜい最適ではないことに同意します。あなたが述べた問題に加えて、それはまたソフトウェアの初期ロード時間が遅いことを意味します。たとえば、nodejs内では、関数がめったに使用されない場合に、関数にモジュールをロードすることがあります。そのため、アプリケーションはまだそのモジュールをロードしていないため、より速く起動します。

もちろん、requireまたはAMDを直接使用することもできますが、タイピングの利点のいくつかを見逃すことになります。

しかし、本当の問題は、harmony / es6がモジュールをトップレベルに定義し、TSがその提案に従っているように見えるという事実にあると思います。したがって、TSチームが標準から逸脱することなくどれだけのことができるかはわかりません。

于 2012-11-19T17:29:56.243 に答える
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先頭にあるステートメントは inert であり、条件if (someCondition)が真でない限り、モジュールの実際のロードは行われません。

これをテストするには、変更someConditionしてネットワーク タブへの影響を確認するか、生成されたコードを確認します...動的バージョンでは、呼び出し"./mod"には表示されません。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());
        });
    }
});

動的荷重なし

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());
    }
});
于 2012-11-19T09:34:36.883 に答える
1
import { something } from '../here';
import { anything } from '../there';

export const conditionalExport =
  process.env.NODE_ENV === 'production' ? something : anything;

Andrew answerからのインスピレーション。

于 2021-06-16T14:20:02.170 に答える