モジュール - リファレンス

モジュール構文

TypeScriptコンパイラは、TypeScriptファイルおよびJavaScriptファイルで標準のECMAScriptモジュール構文を認識し、JavaScriptファイルでさまざまな形式のCommonJS構文を認識します。

TypeScriptファイルやJSDocコメントで使用できる、いくつかのTypeScript固有の構文拡張もあります。

TypeScript固有の宣言のインポートとエクスポート

型エイリアス、インターフェース、列挙型、名前空間は、標準のJavaScript宣言と同様に、export修飾子を使用してモジュールからエクスポートできます。

ts
// Standard JavaScript syntax...
export function f() {}
// ...extended to type declarations
export type SomeType = /* ... */;
export interface SomeInterface { /* ... */ }

標準のJavaScript宣言への参照と並んで、名前付きエクスポートで参照することもできます。

ts
export { f, SomeType, SomeInterface };

エクスポートされた型(およびその他のTypeScript固有の宣言)は、標準のECMAScriptインポートでインポートできます。

ts
import { f, SomeType, SomeInterface } from "./module.js";

名前空間のインポートまたはエクスポートを使用する場合、エクスポートされた型は、型位置で参照されるときに名前空間で利用できます。

ts
import * as mod from "./module.js";
mod.f();
mod.SomeType; // Property 'SomeType' does not exist on type 'typeof import("./module.js")'
let x: mod.SomeType; // Ok

型のみのインポートとエクスポート

JavaScriptへのインポートとエクスポートを発行するとき、デフォルトでは、TypeScriptは型位置でのみ使用されるインポートと、型のみを参照するエクスポートを自動的に削除(発行しない)します。型のみのインポートとエクスポートを使用して、この動作を強制し、削除を明示的にすることができます。import typeで記述されたインポート宣言、export type { ... }で記述されたエクスポート宣言、およびtypeキーワードがプレフィックスとして付いたインポートまたはエクスポート指定子はすべて、出力JavaScriptから削除されることが保証されています。

ts
// @Filename: main.ts
import { f, type SomeInterface } from "./module.js";
import type { SomeType } from "./module.js";
class C implements SomeInterface {
constructor(p: SomeType) {
f();
}
}
export type { C };
// @Filename: main.js
import { f } from "./module.js";
class C {
constructor(p) {
f();
}
}

値でさえimport typeでインポートできますが、出力JavaScriptには存在しないため、発行しない位置でのみ使用できます。

ts
import type { f } from "./module.js";
f(); // 'f' cannot be used as a value because it was imported using 'import type'
let otherFunction: typeof f = () => {}; // Ok

型のみのインポート宣言は、デフォルトインポートと名前付きバインディングの両方を宣言することはできません。typeがデフォルトインポートに適用されるか、インポート宣言全体に適用されるかが曖昧になるためです。代わりに、インポート宣言を2つに分割するか、defaultを名前付きバインディングとして使用します。

ts
import type fs, { BigIntOptions } from "fs";
// ^^^^^^^^^^^^^^^^^^^^^
// Error: A type-only import can specify a default import or named bindings, but not both.
import type { default as fs, BigIntOptions } from "fs"; // Ok

import()

TypeScriptは、インポート宣言を記述せずにモジュールの型を参照するための、JavaScriptの動的なimportに似た型構文を提供します。

ts
// Access an exported type:
type WriteFileOptions = import("fs").WriteFileOptions;
// Access the type of an exported value:
type WriteFileFunction = typeof import("fs").writeFile;

これは、型をインポートすることができないJavaScriptファイルのJSDocコメントで特に役立ちます。

ts
/** @type {import("webpack").Configuration} */
module.exports = {
// ...
}

export =import = require()

CommonJSモジュールを発行するとき、TypeScriptファイルはmodule.exports = ...const mod = require("...") JavaScript構文の直接のアナログを使用できます。

ts
// @Filename: main.ts
import fs = require("fs");
export = fs.readFileSync("...");
// @Filename: main.js
"use strict";
const fs = require("fs");
module.exports = fs.readFileSync("...");

変数宣言とプロパティの代入はTypeScriptの型を参照できなかったため、特別なTypeScript構文を使用できたため、この構文はJavaScriptの対応物よりも優先して使用されていました。

ts
// @Filename: a.ts
interface Options { /* ... */ }
module.exports = Options; // Error: 'Options' only refers to a type, but is being used as a value here.
export = Options; // Ok
// @Filename: b.ts
const Options = require("./a");
const options: Options = { /* ... */ }; // Error: 'Options' refers to a value, but is being used as a type here.
// @Filename: c.ts
import Options = require("./a");
const options: Options = { /* ... */ }; // Ok

アンビエントモジュール

TypeScriptは、スクリプト(非モジュール)ファイルにおいて、実行時に存在し、対応するファイルがないモジュールを宣言するための構文をサポートしています。これらのアンビエントモジュールは通常、Node.jsにおける"fs""path"のような、実行時によって提供されるモジュールを表します。

ts
declare module "path" {
export function normalize(p: string): string;
export function join(...paths: any[]): string;
export var sep: string;
}

アンビエントモジュールがTypeScriptプログラムにロードされると、TypeScriptは他のファイルで宣言されたモジュールのインポートを認識します。

ts
// 👇 Ensure the ambient module is loaded -
// may be unnecessary if path.d.ts is included
// by the project tsconfig.json somehow.
/// <reference path="path.d.ts" />
import { normalize, join } from "path";

アンビエントモジュールの宣言は、モジュール拡張と構文が同一のため、混同しやすいです。このモジュール宣言の構文は、ファイルがモジュールの場合、つまりトップレベルにimportまたはexportステートメントがある場合(または--moduleDetection forceまたはautoの影響を受ける場合)、モジュール拡張になります。

ts
// Not an ambient module declaration anymore!
export {};
declare module "path" {
export function normalize(p: string): string;
export function join(...paths: any[]): string;
export var sep: string;
}

アンビエントモジュールは、モジュール宣言の本体内でインポートを使用して、包含するファイルをモジュールに変換することなく(アンビエントモジュール宣言をモジュール拡張にする)、他のモジュールを参照することができます。

ts
declare module "m" {
// Moving this outside "m" would totally change the meaning of the file!
import { SomeType } from "other";
export function f(): SomeType;
}

パターンアンビエントモジュールは、その名前に単一の*ワイルドカード文字を含み、インポートパス内の0個以上の文字に一致します。これは、カスタムローダーによって提供されるモジュールを宣言するのに役立ちます。

ts
declare module "*.html" {
const content: string;
export default content;
}

moduleコンパイラオプション

このセクションでは、各moduleコンパイラオプションの値の詳細について説明します。オプションの内容と、コンパイルプロセス全体における位置づけについては、モジュール出力形式の理論セクションを参照してください。簡単に言えば、moduleコンパイラオプションは、歴史的には、出力されるJavaScriptファイルのモジュール形式を制御するためにのみ使用されていました。しかし、最近のnode16およびnodenextの値は、Node.jsのモジュールシステムの幅広い特性、サポートされているモジュール形式、各ファイルのモジュール形式の決定方法、異なるモジュール形式が相互運用する方法などを記述しています。

node16, nodenext

Node.jsは、CommonJSとECMAScriptモジュールの両方をサポートしており、各ファイルがどの形式になるか、および2つの形式がどのように相互運用できるかについての特定のルールがあります。node16nodenextは、Node.jsのデュアル形式モジュールシステムのすべての動作を記述しており、CommonJSまたはESM形式のいずれかでファイルを出力します。これは、実行環境に依存せず、すべての出力ファイルを単一の形式に強制し、出力が実行環境に対して有効であることをユーザーが保証する必要がある他のすべてのmoduleオプションとは異なります。

よくある誤解は、node16nodenextがESモジュールのみを出力するということです。実際には、node16nodenextは、ESモジュールを使用するプロジェクトだけでなく、ESモジュールをサポートするNode.jsのバージョンを記述しています。各ファイルの検出されたモジュール形式に基づいて、ESMとCommonJSの両方の出力がサポートされています。node16nodenextは、Node.jsのデュアルモジュールシステムの複雑さを反映する唯一のmoduleオプションであるため、ESモジュールを使用するかどうかにかかわらず、Node.js v12以降で実行することを目的としたすべてのアプリとライブラリにとって、唯一正しいmoduleオプションです。

node16nodenextは現在同一であり、異なるtargetオプション値を暗示するという例外があります。Node.jsが将来モジュールシステムに大幅な変更を加えた場合、node16は凍結され、nodenextは新しい動作を反映するように更新されます。

モジュール形式の検出

  • .mts/.mjs/.d.mtsファイルは常にESモジュールです。
  • .cts/.cjs/.d.ctsファイルは常にCommonJSモジュールです。
  • .ts/.tsx/.js/.jsx/.d.tsファイルは、最も近い祖先のpackage.jsonファイルに"type": "module"が含まれている場合はESモジュール、それ以外の場合はCommonJSモジュールです。

入力された.ts/.tsx/.mts/.ctsファイルの検出されたモジュール形式によって、出力されるJavaScriptファイルのモジュール形式が決まります。たとえば、.tsファイルのみで構成されるプロジェクトは、--module nodenextの場合、デフォルトですべてCommonJSモジュールを出力し、プロジェクトのpackage.jsonに"type": "module"を追加することで、すべてESモジュールを出力させることができます。

相互運用性のルール

  • ESモジュールがCommonJSモジュールを参照する場合
    • CommonJSモジュールのmodule.exportsは、ESモジュールへのデフォルトインポートとして利用できます。
    • CommonJSモジュールのmodule.exportsのプロパティ(default以外)は、ESモジュールへの名前付きインポートとして利用できる場合とできない場合があります。Node.jsは、静的解析によってそれらを利用できるように試みます。TypeScriptは、宣言ファイルからその静的解析が成功するかどうかを知ることができず、成功すると楽観的に仮定します。これにより、TypeScriptは実行時にクラッシュする可能性のある名前付きインポートをキャッチする能力が制限されます。詳細については、#54018を参照してください。
  • CommonJSモジュールがESモジュールを参照する場合
    • requireはESモジュールを参照できません。TypeScriptの場合、これは検出されたCommonJSモジュールであるファイル内のimportステートメントを含みます。これらのimportステートメントは、出力されるJavaScriptでrequire呼び出しに変換されるためです。
    • 動的なimport()呼び出しを使用して、ESモジュールをインポートできます。これは、モジュールのモジュール名前空間オブジェクト(別のESモジュールからのimport * as ns from "./module.js"から取得できるもの)のPromiseを返します。

出力

各ファイルの出力形式は、各ファイルの検出されたモジュール形式によって決まります。ESM出力は--module esnextと似ていますが、--module esnextでは許可されていないimport x = require("...")に対して特別な変換があります。

ts
import x = require("mod");
js
import { createRequire as _createRequire } from "module";
const __require = _createRequire(import.meta.url);
const x = __require("mod");

CommonJS出力は--module commonjsと似ていますが、動的なimport()呼び出しは変換されません。ここで表示される出力は、esModuleInteropが有効になっている状態です。

ts
import fs from "fs"; // transformed
const dynamic = import("mod"); // not transformed
js
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = __importDefault(require("fs")); // transformed
const dynamic = import("mod"); // not transformed

暗黙的および強制的なオプション

  • --module nodenextまたはnode16は、同じ名前でmoduleResolutionを暗黙的に指定し、強制します。
  • --module nodenextは、--target esnextを暗黙的に指定します。
  • --module node16は、--target es2022を暗黙的に指定します。
  • --module nodenextまたはnode16は、--esModuleInteropを暗黙的に指定します。

まとめ

  • node16nodenextは、ESモジュールを使用するかどうかにかかわらず、Node.js v12以降で実行することを目的としたすべてのアプリとライブラリにとって、唯一正しいmoduleオプションです。
  • node16nodenextは、各ファイルの検出されたモジュール形式に基づいて、CommonJSまたはESM形式のいずれかでファイルを出力します。
  • ESMとCJS間のNode.jsの相互運用性ルールは、型チェックに反映されます。
  • ESM出力は、import x = require("...")を、createRequireインポートから構築されたrequire呼び出しに変換します。
  • CommonJS出力は、動的なimport()呼び出しを変換せずに残すため、CommonJSモジュールはESモジュールを非同期的にインポートできます。

es2015, es2020, es2022, esnext

概要

  • バンドラー、Bun、tsxでは、--moduleResolution bundlerと一緒にesnextを使用してください。
  • Node.jsには使用しないでください。Node.js用のESモジュールを出力するには、package.jsonで"type": "module"とともにnode16またはnodenextを使用してください。
  • import mod = require("mod")は、宣言ファイル以外では許可されていません。
  • es2020は、import.metaプロパティのサポートを追加します。
  • es2022は、トップレベルのawaitのサポートを追加します。
  • esnextは、ECMAScriptモジュールへのStage 3提案のサポートを含める可能性のある、動きのあるターゲットです。
  • 出力されるファイルはESモジュールですが、依存関係は任意の形式にすることができます。

ts
import x, { y, z } from "mod";
import * as mod from "mod";
const dynamic = import("mod");
console.log(x, y, z, mod, dynamic);
export const e1 = 0;
export default "default export";
js
import x, { y, z } from "mod";
import * as mod from "mod";
const dynamic = import("mod");
console.log(x, y, z, mod, dynamic);
export const e1 = 0;
export default "default export";

commonjs

概要

  • おそらくこれを使用すべきではありません。Node.js用のCommonJSモジュールを出力するには、node16またはnodenextを使用してください。
  • 出力されるファイルはCommonJSモジュールですが、依存関係は任意の形式にすることができます。
  • 動的なimport()は、require()呼び出しのPromiseに変換されます。
  • esModuleInteropは、デフォルトおよび名前空間インポートの出力コードに影響します。

出力はesModuleInterop: falseで表示されます。

ts
import x, { y, z } from "mod";
import * as mod from "mod";
const dynamic = import("mod");
console.log(x, y, z, mod, dynamic);
export const e1 = 0;
export default "default export";
js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.e1 = void 0;
const mod_1 = require("mod");
const mod = require("mod");
const dynamic = Promise.resolve().then(() => require("mod"));
console.log(mod_1.default, mod_1.y, mod_1.z, mod);
exports.e1 = 0;
exports.default = "default export";
ts
import mod = require("mod");
console.log(mod);
export = {
p1: true,
p2: false
};
js
"use strict";
const mod = require("mod");
console.log(mod);
module.exports = {
p1: true,
p2: false
};

system

概要

ts
import x, { y, z } from "mod";
import * as mod from "mod";
const dynamic = import("mod");
console.log(x, y, z, mod, dynamic);
export const e1 = 0;
export default "default export";
js
System.register(["mod"], function (exports_1, context_1) {
"use strict";
var mod_1, mod, dynamic, e1;
var __moduleName = context_1 && context_1.id;
return {
setters: [
function (mod_1_1) {
mod_1 = mod_1_1;
mod = mod_1_1;
}
],
execute: function () {
dynamic = context_1.import("mod");
console.log(mod_1.default, mod_1.y, mod_1.z, mod, dynamic);
exports_1("e1", e1 = 0);
exports_1("default", "default export");
}
};
});

amd

概要

  • RequireJSのようなAMDローダー用に設計されています。
  • おそらくこれを使用すべきではありません。代わりにバンドラーを使用してください。
  • 出力されるファイルはAMDモジュールですが、依存関係は任意の形式にすることができます。
  • outFileをサポートします。

ts
import x, { y, z } from "mod";
import * as mod from "mod";
const dynamic = import("mod");
console.log(x, y, z, mod, dynamic);
export const e1 = 0;
export default "default export";
js
define(["require", "exports", "mod", "mod"], function (require, exports, mod_1, mod) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.e1 = void 0;
const dynamic = new Promise((resolve_1, reject_1) => { require(["mod"], resolve_1, reject_1); });
console.log(mod_1.default, mod_1.y, mod_1.z, mod, dynamic);
exports.e1 = 0;
exports.default = "default export";
});

umd

概要

  • AMDまたはCommonJSローダー用に設計されています。
  • 他のほとんどのUMDラッパーのようにグローバル変数を公開しません。
  • おそらくこれを使用すべきではありません。代わりにバンドラーを使用してください。
  • 出力されるファイルはUMDモジュールですが、依存関係は任意の形式にすることができます。

ts
import x, { y, z } from "mod";
import * as mod from "mod";
const dynamic = import("mod");
console.log(x, y, z, mod, dynamic);
export const e1 = 0;
export default "default export";
js
(function (factory) {
if (typeof module === "object" && typeof module.exports === "object") {
var v = factory(require, exports);
if (v !== undefined) module.exports = v;
}
else if (typeof define === "function" && define.amd) {
define(["require", "exports", "mod", "mod"], factory);
}
})(function (require, exports) {
"use strict";
var __syncRequire = typeof module === "object" && typeof module.exports === "object";
Object.defineProperty(exports, "__esModule", { value: true });
exports.e1 = void 0;
const mod_1 = require("mod");
const mod = require("mod");
const dynamic = __syncRequire ? Promise.resolve().then(() => require("mod")) : new Promise((resolve_1, reject_1) => { require(["mod"], resolve_1, reject_1); });
console.log(mod_1.default, mod_1.y, mod_1.z, mod, dynamic);
exports.e1 = 0;
exports.default = "default export";
});

moduleResolutionコンパイラーオプション

このセクションでは、複数のmoduleResolutionモードで共有されるモジュール解決の機能とプロセスについて説明し、次に各モードの詳細を指定します。オプションの内容とコンパイルプロセス全体での適合性に関する背景については、モジュール解決の理論セクションを参照してください。簡単に言うと、moduleResolutionは、TypeScriptがモジュール指定子import/export/requireステートメントの文字列リテラル)をディスク上のファイルに解決する方法を制御し、ターゲットランタイムまたはバンドラーで使用されるモジュールリゾルバーと一致するように設定する必要があります。

共通の機能とプロセス

ts
import x from "./mod.js";
// Runtime lookup: "./mod.js"
// TypeScript lookup #1: "./mod.ts"
// TypeScript lookup #2: "./mod.d.ts"
// TypeScript lookup #3: "./mod.js"

TypeScript のモジュール解決がこの方法で機能する理由については、TypeScript はホストのモジュール解決を模倣しますが、型を使用します を参照してください。

相対ファイルパス解決

TypeScript のすべての moduleResolution アルゴリズムは、ファイル拡張子を含む相対パスでモジュールを参照することをサポートしています(これは上記のルールに従って置換されます)。

ts
// @Filename: a.ts
export {};
// @Filename: b.ts
import {} from "./a.js"; // ✅ Works in every `moduleResolution`

拡張子なしの相対パス

一部のケースでは、ランタイムまたはバンドラーは相対パスから .js ファイル拡張子を省略できます。TypeScript は、moduleResolution 設定とコンテキストが、ランタイムまたはバンドラーがそれをサポートすることを示している場合、この動作をサポートします。

ts
// @Filename: a.ts
export {};
// @Filename: b.ts
import {} from "./a";

TypeScript が、モジュール指定子 "./a" が与えられた場合、ランタイムが ./a.js の検索を実行すると判断した場合、./a.js拡張子置換を受け、この例ではファイル a.ts に解決されます。

拡張子なしの相対パスは、Node.js の import パスではサポートされておらず、package.json ファイルで指定されたファイルパスでは常にサポートされているわけではありません。TypeScript は現在、一部のランタイムやバンドラーがサポートしている場合でも、.mjs/.mts または .cjs/.cts ファイル拡張子の省略をサポートしていません。

ディレクトリモジュール(インデックスファイル解決)

場合によっては、ファイルではなくディレクトリをモジュールとして参照できます。最も単純で一般的なケースでは、ランタイムまたはバンドラーがディレクトリ内の index.js ファイルを探します。TypeScript は、moduleResolution 設定とコンテキストが、ランタイムまたはバンドラーがそれをサポートすることを示している場合、この動作をサポートします。

ts
// @Filename: dir/index.ts
export {};
// @Filename: b.ts
import {} from "./dir";

TypeScript が、モジュール指定子 "./dir" が与えられた場合、ランタイムが ./dir/index.js の検索を実行すると判断した場合、./dir/index.js拡張子置換を受け、この例ではファイル dir/index.ts に解決されます。

ディレクトリモジュールには、package.json ファイルを含めることもできます。このファイルでは、"main" および "types" フィールドの解決がサポートされており、index.js の検索よりも優先されます。"typesVersions" フィールドも、ディレクトリモジュールでサポートされています。

ディレクトリモジュールは、node_modules パッケージと同じではなく、パッケージで利用できる機能のサブセットのみをサポートしており、一部のコンテキストではまったくサポートされていません。Node.js はそれらをレガシー機能と見なしています。

paths

概要

TypeScript は、paths コンパイラオプションを使用して、ベア指定子のコンパイラのモジュール解決をオーバーライドする方法を提供します。この機能はもともと AMD モジュールローダー(ESM が存在したり、バンドラーが広く使用されるようになる前に、ブラウザーでモジュールを実行する手段)で使用されるように設計されましたが、現在でも、TypeScript がモデル化していないモジュール解決機能をランタイムまたはバンドラーがサポートしている場合に使用できます。たとえば、--experimental-network-imports を使用して Node.js を実行している場合、特定の https:// インポートに対してローカル型定義ファイルを手動で指定できます。

json
{
"compilerOptions": {
"module": "nodenext",
"paths": {
"https://esm.sh/lodash@4.17.21": ["./node_modules/@types/lodash/index.d.ts"]
}
}
}
ts
// Typed by ./node_modules/@types/lodash/index.d.ts due to `paths` entry
import { add } from "https://esm.sh/lodash@4.17.21";

バンドラーで構築されたアプリがバンドラー構成で便利なパスエイリアスを定義し、paths でそれらのエイリアスを TypeScript に通知することも一般的です。

json
{
"compilerOptions": {
"module": "esnext",
"moduleResolution": "bundler",
"paths": {
"@app/*": ["./src/*"]
}
}
}
paths は emit に影響を与えません

paths オプションは、TypeScript によって emit されたコード内のインポートパスを変更しません。したがって、TypeScript では動作するように見えるが、ランタイムでクラッシュするパスエイリアスを非常に簡単に作成できます。

json
{
"compilerOptions": {
"module": "nodenext",
"paths": {
"node-has-no-idea-what-this-is": ["./oops.ts"]
}
}
}
ts
// TypeScript: ✅
// Node.js: 💥
import {} from "node-has-no-idea-what-this-is";

バンドルされたアプリが paths を設定するのは問題ありませんが、公開されたライブラリは設定しないことが非常に重要です。これは、ユーザーが TypeScript とバンドラーの両方に対して同じエイリアスを設定しないと、emit された JavaScript がライブラリのコンシューマーに対して機能しないためです。ライブラリとアプリの両方で、便利な paths エイリアスの標準的な代替として、package.json "imports" を検討できます。

paths は monorepo パッケージまたは node_modules パッケージを指すべきではありません

paths エイリアスと一致するモジュール指定子はベア指定子ですが、エイリアスが解決されると、モジュール解決は相対パスとして解決されたパスで続行されます。したがって、package.json の "exports" フィールドのサポートなど、node_modules パッケージ検索で発生する解決機能は、paths エイリアスが一致した場合には有効になりません。これにより、pathsnode_modules パッケージを指す場合、予期しない動作につながる可能性があります。

ts
{
"compilerOptions": {
"paths": {
"pkg": ["./node_modules/pkg/dist/index.d.ts"],
"pkg/*": ["./node_modules/pkg/*"]
}
}
}

この構成は、パッケージ解決の動作の一部をシミュレートする場合がありますが、パッケージの package.json ファイルで定義されている maintypesexportstypesVersions をすべてオーバーライドし、パッケージからのインポートはランタイムで失敗する可能性があります。

同じ注意点が、monorepo 内で相互に参照し合うパッケージにも当てはまります。paths を使用して TypeScript に "@my-scope/lib" を兄弟パッケージに人為的に解決させる代わりに、npmyarn、または pnpm を介してワークスペースを使用して、パッケージを node_modules にシンボリックリンクするのが最善です。これにより、TypeScript とランタイムまたはバンドラーの両方が実際の node_modules パッケージ検索を実行できます。これは、monorepo パッケージが npm に公開される場合に特に重要です。パッケージはユーザーによってインストールされると node_modules パッケージ検索を介して相互に参照し合い、ワークスペースを使用すると、ローカル開発中にその動作をテストできます。

baseUrl との関係

baseUrl が指定されている場合、各 paths 配列の値は baseUrl を基準に解決されます。それ以外の場合は、それらを定義する tsconfig.json ファイルを基準に解決されます。

ワイルドカード置換

paths パターンには、任意の文字列に一致する単一の * ワイルドカードを含めることができます。次に、* トークンをファイルパスの値で使用して、一致した文字列を置換できます。

json
{
"compilerOptions": {
"paths": {
"@app/*": ["./src/*"]
}
}
}

"@app/components/Button" のインポートを解決するとき、TypeScript は @app/* に一致させ、*components/Button にバインドし、次に tsconfig.json パスを基準にしてパス ./src/components/Button を解決しようとします。この検索の残りの部分は、moduleResolution 設定に従って、他の 相対パス検索 と同じルールに従います。

複数のパターンがモジュール指定子に一致する場合、* トークンの前の最長一致プレフィックスを持つパターンが使用されます。

json
{
"compilerOptions": {
"paths": {
"*": ["./src/foo/one.ts"],
"foo/*": ["./src/foo/two.ts"],
"foo/bar": ["./src/foo/three.ts"]
}
}
}

"foo/bar" のインポートを解決する場合、3 つの paths パターンすべてが一致しますが、"foo/bar""foo/" および "" よりも長いため、最後のパターンが使用されます。

フォールバック

パスマッピングには複数のファイルパスを指定できます。1つのパスの解決に失敗した場合、解決が成功するか配列の終わりに達するまで、配列内の次のパスが試行されます。

json
{
"compilerOptions": {
"paths": {
"*": ["./vendor/*", "./types/*"]
}
}
}

baseUrl

baseUrl は、AMD モジュールローダーで使用するために設計されました。AMD モジュールローダーを使用していない場合は、おそらく baseUrl を使用しないでください。TypeScript 4.1 以降、paths を使用するために baseUrl は必須ではなくなり、paths 値が解決されるディレクトリを設定するためだけに使用すべきではありません。

baseUrl コンパイラオプションは、任意の moduleResolution モードと組み合わせて使用でき、(./../、または / で始まらない)ベア指定子を解決するディレクトリを指定します。baseUrl は、それらをサポートする moduleResolution モードにおいて、node_modules パッケージ検索よりも優先度が高くなります。

baseUrl 検索を実行する場合、解決は他の相対パス解決と同じルールに従って進められます。たとえば、拡張子なしの相対パスをサポートする moduleResolution モードでは、baseUrl/src に設定されている場合、モジュール指定子 "some-file"/src/some-file.ts に解決される可能性があります。

相対モジュール指定子の解決は、baseUrl オプションの影響を受けることはありません。

node_modules パッケージ検索

Node.js は、相対パス、絶対パス、または URL ではないモジュール指定子を、node_modules サブディレクトリ内で検索するパッケージへの参照として扱います。バンドラーは、ユーザーが Node.js と同じ依存関係管理システム、場合によっては同じ依存関係を使用できるように、この動作を便利に採用しました。TypeScript の classic を除くすべての moduleResolution オプションは、node_modules 検索をサポートしています。(classic は、他の解決手段が失敗した場合に node_modules/@types の検索をサポートしますが、node_modules で直接パッケージを探すことはありません。) すべての node_modules パッケージ検索には、次の構造があります(pathsbaseUrl、自己名インポート、package.json "imports" 検索など、優先度の高いベア指定子ルールが使い果たされた後に開始されます)。

  1. インポート元のファイルの各上位ディレクトリについて、その中に node_modules ディレクトリが存在する場合
    1. パッケージと同じ名前のディレクトリが node_modules 内に存在する場合
      1. パッケージディレクトリから型を解決しようとします。
      2. 結果が見つかった場合は、それを返して検索を停止します。
    2. パッケージと同じ名前のディレクトリが node_modules/@types 内に存在する場合
      1. @types パッケージディレクトリから型を解決しようとします。
      2. 結果が見つかった場合は、それを返して検索を停止します。
  2. 以前の検索をすべての node_modules ディレクトリで繰り返しますが、今回は JavaScript ファイルを結果として許可し、@types ディレクトリでは検索しません。

すべての moduleResolution モード(classic を除く)は、このパターンに従いますが、一度見つかったパッケージディレクトリから解決する方法の詳細は異なり、次のセクションで説明します。

package.json "exports"

moduleResolutionnode16nodenext、または bundler に設定され、resolvePackageJsonExports が無効になっていない場合、TypeScript は、ベア指定子 node_modules パッケージ検索によってトリガーされたパッケージディレクトリから解決するときに、Node.js の package.json "exports" 仕様に従います。

"exports" を介してモジュール指定子をファイルパスに解決するための TypeScript の実装は、Node.js に正確に従います。ただし、ファイルパスが解決された後でも、TypeScript は型の検索を優先するために複数のファイル拡張子を試します

条件付き "exports" を介して解決する場合、TypeScript は常に "types" および "default" 条件が存在する場合はそれらに一致させます。さらに、TypeScript は "types@{selector}" という形式のバージョン付きの型条件に({selector}"typesVersions" に実装されているのと同じバージョン一致ルールに従った "typesVersions" 互換のバージョンセレクターです)一致させます。その他の構成不能な条件は moduleResolution モードに依存し、次のセクションで指定します。customConditions コンパイラオプションで一致する追加の条件を構成できます。

"exports" の存在は、"exports" 内で明示的にリストされているかパターンで一致しているサブパス以外は解決されないことに注意してください。

例:サブパス、条件、および拡張子置換

シナリオ:"pkg/subpath" は、以下の package.json を持つパッケージディレクトリで、条件 ["types", "node", "require"]moduleResolution 設定とモジュール解決リクエストをトリガーしたコンテキストによって決定)でリクエストされます。

json
{
"name": "pkg",
"exports": {
".": {
"import": "./index.mjs",
"require": "./index.cjs"
},
"./subpath": {
"import": "./subpath/index.mjs",
"require": "./subpath/index.cjs"
}
}
}

パッケージディレクトリ内の解決プロセス

  1. "exports" は存在しますか? はい。
  2. "exports""./subpath" エントリはありますか? はい。
  3. exports["./subpath"] の値はオブジェクトです。条件を指定する必要があります。
  4. 最初の条件 "import" はこのリクエストに一致しますか? いいえ。
  5. 2 番目の条件 "require" はこのリクエストに一致しますか? はい。
  6. パス "./subpath/index.cjs" に認識された TypeScript ファイル拡張子はありますか? いいえ、したがって拡張子置換を使用します。
  7. 拡張子置換により、次のパスを試して、最初に存在するパスを返すか、それ以外の場合は undefined を返します。
    1. ./subpath/index.cts
    2. ./subpath/index.d.cts
    3. ./subpath/index.cjs

./subpath/index.cts または ./subpath.d.cts が存在する場合、解決は完了です。それ以外の場合、解決は、node_modules パッケージ検索ルールに従って、型を解決しようとして node_modules/@types/pkg およびその他の node_modules ディレクトリを検索します。型が見つからない場合、すべての node_modules を通る 2 回目のパスは ./subpath/index.cjs(存在する場合)に解決され、これは解決に成功したとみなされますが、型を提供しないため、any 型のインポートと、有効になっている場合は noImplicitAny エラーが発生します。

例:明示的な"types"条件

シナリオ:"pkg/subpath" が、条件 ["types", "node", "import"]moduleResolution 設定とモジュール解決リクエストをトリガーしたコンテキストによって決定される)とともに、以下の package.json を持つパッケージディレクトリでリクエストされます。

json
{
"name": "pkg",
"exports": {
"./subpath": {
"import": {
"types": "./types/subpath/index.d.mts",
"default": "./es/subpath/index.mjs"
},
"require": {
"types": "./types/subpath/index.d.cts",
"default": "./cjs/subpath/index.cjs"
}
}
}
}

パッケージディレクトリ内の解決プロセス

  1. "exports" は存在しますか? はい。
  2. "exports""./subpath" エントリはありますか? はい。
  3. exports["./subpath"] の値はオブジェクトです。条件を指定する必要があります。
  4. 最初の条件 "import" はこのリクエストと一致しますか? はい。
  5. exports["./subpath"].import の値はオブジェクトです。これは条件を指定している必要があります。
  6. 最初の条件 "types" はこのリクエストと一致しますか? はい。
  7. パス "./types/subpath/index.d.mts" は認識された TypeScript ファイル拡張子を持っていますか? はい、なので拡張子置換は使用しません。
  8. ファイルが存在する場合はパス "./types/subpath/index.d.mts" を、それ以外の場合は undefined を返します。
例:バージョン付き"types"条件

シナリオ:TypeScript 4.7.5 を使用し、"pkg/subpath" が、条件 ["types", "node", "import"]moduleResolution 設定とモジュール解決リクエストをトリガーしたコンテキストによって決定される)とともに、以下の package.json を持つパッケージディレクトリでリクエストされます。

json
{
"name": "pkg",
"exports": {
"./subpath": {
"types@>=5.2": "./ts5.2/subpath/index.d.ts",
"types@>=4.6": "./ts4.6/subpath/index.d.ts",
"types": "./tsold/subpath/index.d.ts",
"default": "./dist/subpath/index.js"
}
}
}

パッケージディレクトリ内の解決プロセス

  1. "exports" は存在しますか? はい。
  2. "exports""./subpath" エントリはありますか? はい。
  3. exports["./subpath"] の値はオブジェクトです。条件を指定する必要があります。
  4. 最初の条件 "types@>=5.2" はこのリクエストと一致しますか? いいえ、4.7.5 は 5.2 以上ではありません。
  5. 2 番目の条件 "types@>=4.6" はこのリクエストと一致しますか? はい、4.7.5 は 4.6 以上です。
  6. パス "./ts4.6/subpath/index.d.ts" は認識された TypeScript ファイル拡張子を持っていますか? はい、なので拡張子置換は使用しません。
  7. ファイルが存在する場合はパス "./ts4.6/subpath/index.d.ts" を、それ以外の場合は undefined を返します。
例:サブパスパターン

シナリオ:"pkg/wildcard.js" が、条件 ["types", "node", "import"]moduleResolution 設定とモジュール解決リクエストをトリガーしたコンテキストによって決定される)とともに、以下の package.json を持つパッケージディレクトリでリクエストされます。

json
{
"name": "pkg",
"type": "module",
"exports": {
"./*.js": {
"types": "./types/*.d.ts",
"default": "./dist/*.js"
}
}
}

パッケージディレクトリ内の解決プロセス

  1. "exports" は存在しますか? はい。
  2. "exports""./wildcard.js" エントリを持っていますか? いいえ。
  3. * を含むキーで "./wildcard.js" に一致するものはありますか? はい、"./*.js" が一致し、wildcard が置換となるように設定されます。
  4. exports["./*.js"] の値はオブジェクトです。これは条件を指定している必要があります。
  5. 最初の条件 "types" はこのリクエストと一致しますか? はい。
  6. ./types/*.d.ts で、* を置換 wildcard に置き換えます。 ./types/wildcard.d.ts
  7. パス "./types/wildcard.d.ts" は認識された TypeScript ファイル拡張子を持っていますか? はい、なので拡張子置換は使用しません。
  8. ファイルが存在する場合はパス "./types/wildcard.d.ts" を、それ以外の場合は undefined を返します。
例:"exports" が他のサブパスをブロックする

シナリオ:"pkg/dist/index.js" が、以下の package.json を持つパッケージディレクトリでリクエストされます。

json
{
"name": "pkg",
"main": "./dist/index.js",
"exports": "./dist/index.js"
}

パッケージディレクトリ内の解決プロセス

  1. "exports" は存在しますか? はい。
  2. exports の値は文字列です。これはパッケージルート (".") のファイルパスである必要があります。
  3. リクエスト "pkg/dist/index.js" はパッケージルートに対するものですか? いいえ、サブパス dist/index.js を持っています。
  4. 解決に失敗しました。undefined を返します。

"exports" がない場合、リクエストは成功した可能性がありますが、"exports" が存在することで、"exports" を介して一致させることができないサブパスの解決が妨げられます。

package.json "typesVersions"

node_modules パッケージまたはディレクトリモジュールは、package.json に "typesVersions" フィールドを指定して、TypeScript コンパイラのバージョンに応じて、また、node_modules パッケージの場合、解決されているサブパスに応じて TypeScript の解決プロセスをリダイレクトできます。これにより、パッケージの作成者は、1 組の型定義に新しい TypeScript 構文を含めながら、古い TypeScript バージョンとの下位互換性のためにもう 1 組の型定義を提供できます(downlevel-dts のようなツールを使用)。"typesVersions" はすべての moduleResolution モードでサポートされています。ただし、package.json "exports" が読み込まれる状況では、このフィールドは読み込まれません。

例:すべてのリクエストをサブディレクトリにリダイレクトする

シナリオ:モジュールが TypeScript 5.2 を使用して "pkg" をインポートする場合、node_modules/pkg/package.json は次のようになります。

json
{
"name": "pkg",
"version": "1.0.0",
"types": "./index.d.ts",
"typesVersions": {
">=3.1": {
"*": ["ts3.1/*"]
}
}
}

解決プロセス

  1. (コンパイラオプションに応じて)"exports" は存在しますか? いいえ。
  2. "typesVersions" は存在しますか? はい。
  3. TypeScript のバージョンは >=3.1 ですか? はい。マッピング "*": ["ts3.1/*"] を覚えておいてください。
  4. パッケージ名の後にサブパスを解決していますか? いいえ、ルートの "pkg" のみです。
  5. "types" は存在しますか? はい。
  6. "typesVersions" のキーで ./index.d.ts に一致するものはありますか? はい、"*" が一致し、index.d.ts が置換となるように設定されます。
  7. ts3.1/* で、* を置換 ./index.d.ts に置き換えます。ts3.1/index.d.ts
  8. パス ./ts3.1/index.d.ts は認識された TypeScript ファイル拡張子を持っていますか? はい、なので拡張子置換は使用しません。
  9. ファイルが存在する場合はパス ./ts3.1/index.d.ts を、それ以外の場合は undefined を返します。
例:特定ファイルのリクエストをリダイレクトする

シナリオ:モジュールが TypeScript 3.9 を使用して "pkg" をインポートする場合、node_modules/pkg/package.json は次のようになります。

json
{
"name": "pkg",
"version": "1.0.0",
"types": "./index.d.ts",
"typesVersions": {
"<4.0": { "index.d.ts": ["index.v3.d.ts"] }
}
}

解決プロセス

  1. (コンパイラオプションに応じて)"exports" は存在しますか? いいえ。
  2. "typesVersions" は存在しますか? はい。
  3. TypeScript のバージョンは <4.0 ですか? はい。マッピング "index.d.ts": ["index.v3.d.ts"] を覚えておいてください。
  4. パッケージ名の後にサブパスを解決していますか? いいえ、ルートの "pkg" のみです。
  5. "types" は存在しますか? はい。
  6. "typesVersions" のキーで ./index.d.ts に一致するものはありますか? はい、"index.d.ts" が一致します。
  7. パス ./index.v3.d.ts は認識された TypeScript ファイル拡張子を持っていますか? はい、なので拡張子置換は使用しません。
  8. ファイルが存在する場合はパス ./index.v3.d.ts を、それ以外の場合は undefined を返します。

package.json "main" および "types"

ディレクトリのpackage.json "exports" フィールドが読み込まれない場合(コンパイラオプションのため、または存在しないため、またはディレクトリがnode_modules パッケージの代わりにディレクトリモジュールとして解決されているため)、モジュール指定子がパッケージ名または package.json を含むディレクトリの後にサブパスを持たない場合、TypeScript は、パッケージまたはディレクトリのメインモジュールを見つけるために、以下の package.json フィールドから順番に解決を試みます。

  • "types"
  • "typings" (レガシー)
  • "main"

"types" に記述された宣言ファイルは、"main" に記述された実装ファイルの正確な表現であるとみなされます。"types""typings" が存在しないか、解決できない場合、TypeScriptは "main" フィールドを読み取り、拡張子置換を実行して宣言ファイルを見つけます。

型付きパッケージを npm に公開する場合、拡張子置換package.json の "exports" が不要であっても、"types" フィールドを含めることをお勧めします。npm は package.json に "types" フィールドが含まれている場合にのみ、パッケージレジストリのリストに TS アイコンを表示するからです。

パッケージ相対ファイルパス

package.json の "exports"package.json の "typesVersions" も適用されない場合、ベアパッケージ指定子のサブパスは、適用可能な相対パス解決ルールに従って、パッケージディレクトリに対して相対的に解決されます。[package.json の "exports"] を尊重するモードでは、インポートが "exports" で解決に失敗した場合でも、パッケージの package.json に "exports" フィールドが存在するだけで、この動作はブロックされます。これは上記の例で示されています。一方、インポートが "typesVersions" で解決に失敗した場合、フォールバックとしてパッケージ相対ファイルパス解決が試行されます。

パッケージ相対パスがサポートされている場合、moduleResolution モードとコンテキストを考慮して、他の相対パスと同じルールで解決されます。たとえば、--moduleResolution nodenext では、ディレクトリモジュール拡張子なしのパスは、import ではなく、require 呼び出しでのみサポートされます。

ts
// @Filename: module.mts
import "pkg/dist/foo"; // ❌ import, needs `.js` extension
import "pkg/dist/foo.js"; // ✅
import foo = require("pkg/dist/foo"); // ✅ require, no extension needed

package.json の "imports" と自己名前インポート

moduleResolutionnode16nodenext、または bundler に設定されていて、resolvePackageJsonImports が無効になっていない場合、TypeScript は、インポートするファイルの最も近い祖先の package.json の "imports" フィールドを使用して、# で始まるインポートパスを解決しようとします。同様に、package.json の "exports" ルックアップが有効になっている場合、TypeScript は、インポートするファイルの最も近い祖先の package.json の "name" フィールドの値である、現在のパッケージ名で始まるインポートパスを、その package.json の "exports" フィールドを通じて解決しようとします。これらの機能により、パッケージ内のファイルは、相対インポートパスを置き換えて、同じパッケージ内の他のファイルをインポートできます。

TypeScript は、"imports"自己参照に関して、ファイルパスが解決されるまで、Node.js の解決アルゴリズムに正確に従います。その時点で、解決されている "imports" または "exports" を含む package.json が node_modules の依存関係に属しているのか、コンパイルされているローカルプロジェクトに属しているのか(つまり、そのディレクトリにインポートするファイルを含むプロジェクトの tsconfig.json ファイルが含まれているか)に基づいて、TypeScript の解決アルゴリズムが分岐します。

  • package.json が node_modules 内にある場合、TypeScript は、ファイルパスに認識された TypeScript ファイル拡張子がまだない場合は拡張子置換を適用し、結果のファイルパスの存在を確認します。
  • package.json がローカルプロジェクトの一部である場合、"imports" から解決された出力 JavaScript または宣言ファイルパスを最終的に生成する *入力* TypeScript 実装ファイルを見つけるために、追加のマッピングステップが実行されます。このステップがないと、"imports" パスを解決するコンパイルは、現在のコンパイルに含めることを意図した他の入力ファイルではなく、*前のコンパイル*からの出力ファイルを参照することになります。このマッピングでは、tsconfig.json の outDir/declarationDirrootDir が使用されるため、"imports" を使用するには、通常、明示的な rootDir を設定する必要があります。

このバリエーションにより、パッケージの作成者は、npm に公開されるコンパイル出力のみを参照する "imports" および "exports" フィールドを作成できます。同時に、ローカル開発では元の TypeScript ソースファイルを使用できます。

例: 条件付きローカルプロジェクト

シナリオ: "/src/main.mts" が、tsconfig.json と package.json を持つプロジェクトディレクトリで、条件 ["types", "node", "import"]moduleResolution 設定とモジュール解決リクエストをトリガーしたコンテキストによって決定される)を使用して "#utils" をインポートします。

json
// tsconfig.json
{
"compilerOptions": {
"moduleResolution": "node16",
"resolvePackageJsonImports": true,
"rootDir": "./src",
"outDir": "./dist"
}
}
json
// package.json
{
"name": "pkg",
"imports": {
"#utils": {
"import": "./dist/utils.d.mts",
"require": "./dist/utils.d.cts"
}
}
}

解決プロセス

  1. インポートパスが # で始まるため、"imports" を使用して解決を試みます。
  2. 最も近い祖先の package.json に "imports" は存在しますか? はい。
  3. "imports" オブジェクトに "#utils" は存在しますか? はい。
  4. imports["#utils"] の値はオブジェクトです。条件を指定する必要があります。
  5. 最初の条件 "import" はこのリクエストと一致しますか? はい。
  6. 出力パスを入力パスにマッピングしようとしますか? はい、理由は次のとおりです。
    • package.json は node_modules にありますか? いいえ、ローカルプロジェクトにあります。
    • tsconfig.json は package.json ディレクトリ内にありますか? はい。
  7. ./dist/utils.d.mts で、outDir プレフィックスを rootDir に置き換えます。./src/utils.d.mts
  8. 出力拡張子 .d.mts を対応する入力拡張子 .mts に置き換えます。./src/utils.mts
  9. ファイルが存在する場合、パス "./src/utils.mts" を返します。
  10. それ以外の場合は、ファイルが存在する場合、パス "./dist/utils.d.mts" を返します。
例: サブパスパターンを使用した node_modules の依存関係

シナリオ: "/node_modules/pkg/main.mts" が、package.json を持つ条件 ["types", "node", "import"]moduleResolution 設定とモジュール解決リクエストをトリガーしたコンテキストによって決定される)を使用して "#internal/utils" をインポートします。

json
// /node_modules/pkg/package.json
{
"name": "pkg",
"imports": {
"#internal/*": {
"import": "./dist/internal/*.mjs",
"require": "./dist/internal/*.cjs"
}
}
}

解決プロセス

  1. インポートパスが # で始まるため、"imports" を使用して解決を試みます。
  2. 最も近い祖先の package.json に "imports" は存在しますか? はい。
  3. "imports" オブジェクトに "#internal/utils" は存在しますか? いいえ、パターンマッチを確認します。
  4. * を持つキーが "#internal/utils" に一致しますか? はい、"#internal/*" が一致し、utils が置換対象として設定されます。
  5. imports["#internal/*"] の値はオブジェクトです。条件を指定する必要があります。
  6. 最初の条件 "import" はこのリクエストと一致しますか? はい。
  7. 出力パスを入力パスにマッピングしようとしますか? いいえ、package.json が node_modules 内にあるためです。
  8. ./dist/internal/*.mjs で、* を置換 utils に置き換えます。./dist/internal/utils.mjs
  9. パス ./dist/internal/utils.mjs に認識された TypeScript ファイル拡張子はありますか? いいえ、拡張子置換を試みます。
  10. 拡張子置換により、次のパスを試して、最初に存在するパスを返すか、それ以外の場合は undefined を返します。
    1. ./dist/internal/utils.mts
    2. ./dist/internal/utils.d.mts
    3. ./dist/internal/utils.mjs

node16nodenext

これらのモードは、Node.js v12 以降のモジュール解決動作を反映しています。(node16nodenext は現在同じですが、Node.js が将来モジュールシステムに大幅な変更を加えた場合、node16 はフリーズされ、nodenext は新しい動作を反映するように更新されます。)Node.js では、ECMAScript インポートの解決アルゴリズムは、CommonJS の require 呼び出しのアルゴリズムとは大幅に異なります。解決される各モジュール指定子について、構文とインポートするファイルのモジュール形式が最初に、モジュール指定子がエミットされた JavaScript で import になるか require になるかを決定するために使用されます。その情報は、どの解決アルゴリズムを使用するか(および、package.json の"exports" または"imports""import" または "require" 条件を使用するかどうか)を決定するために、モジュールリゾルバーに渡されます。

CommonJS 形式であると判断されたTypeScript ファイルは、デフォルトで import および export 構文を使用できますが、エミットされた JavaScript は代わりに require および module.exports を使用します。つまり、require アルゴリズムを使用して解決される import ステートメントをよく見かけるということです。これにより混乱が生じる場合は、verbatimModuleSyntax コンパイラーオプションを有効にすることができます。これにより、require 呼び出しとしてエミットされる import ステートメントの使用が禁止されます。

動的 import() 呼び出しは、Node.js の動作に従って、常に import アルゴリズムを使用して解決されることに注意してください。ただし、import() 型は(既存の CommonJS 形式の型宣言との後方互換性のために)インポートするファイルの形式に従って解決されます。

ts
// @Filename: module.mts
import x from "./mod.js"; // `import` algorithm due to file format (emitted as-written)
import("./mod.js"); // `import` algorithm due to syntax (emitted as-written)
type Mod = typeof import("./mod.js"); // `import` algorithm due to file format
import mod = require("./mod"); // `require` algorithm due to syntax (emitted as `require`)
// @Filename: commonjs.cts
import x from "./mod"; // `require` algorithm due to file format (emitted as `require`)
import("./mod.js"); // `import` algorithm due to syntax (emitted as-written)
type Mod = typeof import("./mod"); // `require` algorithm due to file format
import mod = require("./mod"); // `require` algorithm due to syntax (emitted as `require`)

暗黙的および強制的なオプション

  • --moduleResolution node16nodenext は、対応する moduleと組み合わせて使用する必要があります。

サポートされている機能

機能は優先順位の高い順にリストされています。

import require
パス
baseUrl
node_modules パッケージの検索
package.json の "exports" typesnodeimport に一致 typesnoderequire に一致
package.json の "imports" と自己名インポート typesnodeimport に一致 typesnoderequire に一致
package.json の "typesVersions"
パッケージ相対パス exports が存在しない場合 exports が存在しない場合
完全な相対パス
拡張子なしの相対パス
ディレクトリモジュール

bundler

--moduleResolution bundler は、ほとんどの JavaScript バンドラーに共通のモジュール解決の挙動をモデル化しようとします。簡単に言えば、これは、node_modules の検索ディレクトリモジュール、および拡張子なしパスのような、Node.js の CommonJS require 解決アルゴリズムに従来関連付けられていたすべての挙動をサポートすることを意味すると同時に、package.json の "exports"package.json の "imports" のような新しい Node.js の解決機能もサポートすることを意味します。

これは、CommonJS モードで解決する node16 および nodenext の挙動と非常に似ていますが、bundler では、package.json の "exports" および "imports" を解決するために使用される条件は常に "types" および "import" です。理由を理解するために、nodenext.ts ファイルでのインポートに対して何が起こるかを比較してみましょう。

ts
// index.ts
import { foo } from "pkg";

--module nodenext --moduleResolution nodenext では、--module 設定で最初に、インポートが .js ファイルに import または require 呼び出しとして出力されるかどうかを判別し、その情報を TypeScript のモジュールリゾルバーに渡し、"import" または "require" 条件を適切に照合するかどうかを決定します。これにより、TypeScript のモジュール解決プロセスは、入力 .ts ファイルから動作しているにもかかわらず、出力 .js ファイルを実行するときに Node.js のモジュール解決プロセスで発生することと同じになるようにします。

一方、バンドラーを使用する場合、バンドラーは通常、未加工の .ts ファイルを直接処理し、変換されていない import ステートメントでモジュール解決プロセスを実行します。このシナリオでは、TypeScript が import をどのように出力するかを考えることはあまり意味がありません。なぜなら、TypeScript は何も出力するために使用されていないからです。バンドラーに関する限り、importimport であり、requirerequire であるため、package.json の "exports" および "imports" を解決するために使用される条件は、入力 .ts ファイルに表示される構文によって決定されます。同様に、--moduleResolution bundler で TypeScript のモジュール解決プロセスが使用する条件も、入力 TypeScript ファイルの入力構文によって決定されます。require 呼び出しは現在まったく解決されないというだけです。

ts
// Some library file:
declare function require(module: string): any;
// index.ts
import { foo } from "pkg"; // Resolved with "import" condition
import pkg2 = require("pkg"); // Not allowed
const pkg = require("pkg"); // Not an error, but not resolved to anything
// ^? any

TypeScript は現在 --moduleResolution bundlerrequire 呼び出しの解決をサポートしていないため、解決するすべてのものは "import" 条件を使用します。

暗黙的および強制的なオプション

  • --moduleResolution bundler--module esnext オプションとペアにする必要があります。
  • --moduleResolution bundler--allowSyntheticDefaultImports を暗黙的に示します。

サポートされている機能

node10 (旧称 node)

--moduleResolution node は、TypeScript 5.0 で node10 に名前が変更されました (後方互換性のため、node はエイリアスとして保持)。これは、Node.js バージョン v12 より前に存在していた CommonJS モジュール解決アルゴリズムを反映しています。使用すべきではありません。

サポートされている機能

classic

classic は使用しないでください。

TypeScript ドキュメントはオープンソース プロジェクトです。これらのページの改善にご協力ください。プル リクエストを送信してください ❤

このページの貢献者
ABAndrew Branch (6)
HCDCHenrique Carvalho da Cruz (1)

最終更新日: 2024年3月21日