# ファイルモジュールの詳細

TypeScriptのモジュール機能は非常に強力であり、便利な機能です。ここでは、その強力さと実際のユースケースを説明します。

## 説明：commonjs、amd、esモジュール、その他

最初に、このあたりのモジュールシステムの分かりづらい矛盾を明確にする必要があります。私は単に推奨を伝え、このノイズを取り除きたいと思います。その他の動くかもしれない方法をすべて説明することはしません。

同じTypeScriptのコードから`module`オプションに応じて異なるJavaScriptを生成されます。無視できるものは次のとおりです(既に過去のものとなった技術については詳しく説明しません)：

* AMD：使用しないでください。ブラウザでしか使えませんでした。
* SystemJS：良い実験でしたが、ESモジュールによって置き換えられました。
* ESモジュール：モダンなブラウザでのみ利用できます。

これはJavaScriptを生成するためのオプションです。これらのオプションの代わりに、`module:commonjs`を使うことをおすすめします。

どのようにTypeScriptモジュールを書くかについては、まだ意見が完全には、まとまっていません。将来問題が起きることを避けるには下記のようにしてください:

* `import foo = require('foo')`、つまり、`import/require`を避けて、ESモジュールの構文を使用してください。

それではESモジュールの構文を見てみましょう。

> 概要： `module:commonjs`を使い、ESモジュールの構文を使ってモジュールをimport/export/作成します。

## ESモジュールの構文

* 変数(または型)のエクスポートは、キーワード`export`を前に置くだけです。簡単です。

```javascript
// `foo.ts`ファイル
export let someVar = 123;
export type SomeType = {
  foo: string;
};
```

* 変数または型を専用の`export`文でエクスポートする

```javascript
// `foo.ts`ファイル
let someVar = 123;
type SomeType = {
  foo: string;
};
export {
  someVar,
  SomeType
};
```

* 名前を変更して専用の`export`文で変数や型をエクスポートする

```javascript
// `foo.ts`ファイル
let someVar = 123;
export { someVar as aDifferentName };
```

* `import`を使用して変数または型をインポートする

```javascript
// `foo.ts`ファイル
import { someVar, SomeType } from './foo';
```

* 名前を変更して`import`を使って変数や型をインポートする

```javascript
// `bar.ts`ファイル
import { someVar as aDifferentName } from './foo';
```

* `import * as`を使って1つの名前にモジュールすべてをインポートする

  ```javascript
  // `bar.ts`ファイル
  import * as foo from './foo';
  // `foo.someVar`や`foo.SomeType`など`foo.ts`がエクスポートしているものを何でも利用できます
  ```
* 副作用のためだけに1つのファイルをインポートする:

```javascript
import 'core-js'; // 共通のpolyfillライブラリ
```

* 別のモジュールからすべてのものを再エクスポートする

```javascript
export * from './foo';
```

* 別のモジュールから一部のものを再エクスポートする

```javascript
export { someVar } from './foo';
```

* 名前を変更して別のモジュールから一部のものだけを再エクスポートする

```javascript
export { someVar as aDifferentName } from './foo';
```

## デフォルトエクスポート/インポート

あなたが後で知るように、私はデフォルトエクスポートが好きではありません。しかし、知っておく必要があります。そのため、ここで、デフォルトエクスポートの使い方を説明します。

* `export default`を使ってエクスポートする
  * 変数の前に(`let / const / var`は必要ありません)
  * 関数の前
  * クラスの前

```javascript
// 何らかの変数
export default someVar = 123;
// または関数
export default function someFunction() { }
// またはクラス
export default class SomeClass { }
```

* `import someName from "someModule"`という構文を使用してインポートする(インポートしたものには任意の名前を付けることができます):

```javascript
import someLocalNameForThisFile from "../foo";
```

## モジュールのパス解決

> 私は`moduleResolution: commonjs`を指定することを前提にしています。これはあなたのTypeScript設定にも追加しておくべきオプションです。この設定は`module:commonjs`を設定していれば、暗黙的に設定されます。

2つの異なる種類のモジュールがあります。それらは、import文のパス部分によって区別されます(たとえば、`import foo from 'パス'`)。

* 相対パスのモジュール(`.`で始まるパス:`./someFile`、`../../someFolder/someFile`など)
* 動的に参照されるモジュール(`'core-js'`、`'typestyle'`、`'react'`、`'react / core'`など)

主な違いは、モジュールがファイルシステム上でどのように解決されるかです。

### 相対パスの解決

簡単です。単に相対的なパスに従います :)

* ファイル`bar.ts`が`import * as foo from './foo';`を実行した場合、`foo`を同じフォルダに置く必要がある
* ファイル`bar.ts`が`import * as foo from '../foo';`を実行する場合、`foo`は1つ上のフォルダ内に存在する必要がある
* ファイル`bar.ts`が`import * as foo from '../someFolder/foo';`を実行する場合、1つ上のフォルダにfooが存在する`someFolder`というフォルダが存在する必要がある

もしくは他に思いついた相対パスが使えます :)

### 動的な解決

インポートパスが相対でない場合、検索は [Node.jsスタイルのモジュール解決](https://nodejs.org/api/modules.html#modules_all_together) によって行われます。ここでは簡単な例を示します。

* `import * as foo from 'foo'`と書いた場合、以下の場所が順番にチェックされます
  * `./node_modules/foo`
  * `../node_modules/foo`
  * `../../node_modules/foo`
  * ファイルシステムのルートに到達するまで続く
* `import * as foo from 'something/foo'`と書いた場合、以下の場所が順番にチェックされます
  * `./node_modules/something/foo`
  * `../node_modules/something/foo`
  * `../../node_modules/something/foo`
  * ファイルシステムのルートに到達するまで続く

## どのようにパスが解決されるか

上記で言及している場所が「チェックされる」とは、下記のように、その場所がチェックされることを意味しています。例えば`foo`というパスを指定しているとします:

* その場所に、`foo.ts`があれば、解決されます。
* その場所がフォルダで、`foo/index.ts`ファイルがある場合、解決されます。
* その場所がフォルダで、`foo/package.json`が存在し、package.jsonの`types`キーで指定されたファイルがある場合は、解決されます。
* その場所がフォルダで、`package.json`が存在し、package.jsonの`main`キーで指定されたファイルが存在する場合、解決されます。

私が言うファイルは、実際には`.ts`/`.d.ts`と`.js`を意味しています。

以上です。あなたは既にモジュール解決のエキスパートです。

## 型の動的検索を上書きする

あなたは、`declare module '何らかのパス'`を使ってプロジェクトのモジュールをグローバルに宣言することができます。そして、import文はそのパスを魔法のように解決します。

例：

```typescript
// global.d.ts
declare module 'foo' {
  // 何らかの変数の宣言
  export var bar: number; /* 例 */
}
```

そして、このようにすることができます：

```typescript
// anyOtherTsFileInYourProject.ts
import * as foo from 'foo';
// 動的ルックアップを行わない場合、TypeScriptは、 foo を {bar:number} と推測します:
```

## 型だけを`import/require`する

次の文は:

```typescript
import foo = require('foo');
```

実際には2つのことをしています:

* fooモジュールの型情報をインポートする
* fooモジュールの実行時の依存関係を指定する

開発者は、型情報のみをロードし、実行時の依存関係が発生しないようにすることも可能です。この先を理解する前に、[宣言空間](https://typescript-jp.gitbook.io/deep-dive/project/declarationspaces)を読んでおくとよいでしょう。

変数宣言空間にインポートされた名前を使用しない場合、そのインポートは、生成されたJavaScriptから完全に削除されます。例を見るのが最も簡単です。これが理解できたら、ユースケースを紹介します。

### 例1

```typescript
import foo = require('foo');
```

生成されるJavaScript：

```javascript
```

想像の通り、fooが使われないため、空ファイルが生成されます。

### 例2

```typescript
import foo = require('foo');
var bar: foo;
```

生成されるJavaScript：

```javascript
var bar;
```

これは、`foo`(または`foo.bas`などのプロパティ)が変数として一度も使用されないためです。

### 例3

```typescript
import foo = require('foo');
var bar = foo;
```

生成されるJavaScript(commonjsと仮定します):

```javascript
var foo = require('foo');
var bar = foo;
```

これは`foo`が変数として使われているためです。

## ユースケース： 遅延ロード(Lazy loading)

型推論は事前に行う必要があります。これは、ファイル`bar`でファイル`foo`のある型を使用したい場合、次のようにしなければならないことを意味します：

```typescript
import foo = require('foo');
var bar: foo.SomeType;
```

しかし、あるいは実行時に特定の場合だけ`foo`をロードしたいかもしれません。そのような場合には、`import`した名前を型アノテーションとしてのみ使用し、変数として使用しないでください。これにより、TypeScriptにより挿入される実行時依存関係をすべて削除します。そして、あなたは独自のモジュールローダーに固有のコードを書いて実際のモジュールを手動でインポートします。

例として、次の`commonjs`ベースのコードを考えてみましょう。このコードでは、特定の関数が呼び出された時だけ`'foo'`モジュールをロードします：

```typescript
import foo = require('foo');

export function loadFoo() {
    // `foo` を遅延ロードします。そして、オリジナルのモジュールは型アノテーションとして *だけ* 利用します。
    var _foo: typeof foo = require('foo');
    // これで、 `foo` の代わりに `_foo` を変数として扱うことができます。
}
```

`amd`(requirejsを使用)での同様のサンプルは次のようになります：

```typescript
import foo = require('foo');

export function loadFoo() {
    // `foo` を遅延ロードします。そして、オリジナルのモジュールは型アノテーションとして *だけ* 利用します。
    require(['foo'], (_foo: typeof foo) => {
        // これで、 `foo` の代わりに `_foo` を変数として扱うことができます。
    });
}
```

このパターンは一般的に使用されます。

* Webアプリケーションにおいて、特定のルートの場合のみ特定のJavaScriptをロードする
* Nodeアプリケーションにおいて、アプリケーションの起動を高速化したい場合に、特定のモジュールだけをロードする

## ユースケース：循環依存を避ける

遅延ロードの使用例と同様に、特定のモジュールローダ(commonjs/nodeと、amd/requirejs)は循環依存のため、うまく動作しません。そのような場合には、1つの方向に遅延ロードを行うようにし、反対方向のロードの前にロードしておくと便利です。

## ユースケース：確実にインポートする

場合によっては、副作用のためだけにファイルをロードすることもできます(例えば[CodeMirror addons](https://codemirror.net/doc/manual.html#addons)のように、モジュールを他のライブラリに登録させる場合など)。しかし、単に`import/require`を行うと、コンパイルされたJavaScriptがモジュールに依存しておらず、モジュールバンドラ(例えばwebpack)が、そのインポートを完全に無視してしまうかもしれません。このような場合、例えば下記のように `ensureImport`変数を使用して、コンパイルされたJavaScriptがモジュールに依存するようにすることができます。

```typescript
import foo = require('./foo');
import bar = require('./bar');
import bas = require('./bas');
const ensureImport: any =
    foo
    || bar
    || bas;
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://typescript-jp.gitbook.io/deep-dive/project/modules/external-modules.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
