May 07, 2021 TypeScript
This section assumes that you already know some basics about modules Read the module documentation to learn more.
Module resolution refers
to a process that the compiler uses to find out the specific values referenced by an import operation. S
uppose you have an import
import { a } from "moduleA"
In order to check for any
a
the compiler needs to know exactly what it means, and it needs to check its
moduleA
At this point, the compiler wonders,
moduleA
the shape of moduleA?"
This sounds simple, and
moduleA
be in
.ts
/
.tsx
files you write or
.d.ts
First, the compiler tries to locate the file that represents the import module. C
ompilation follows one of two strategies:
Classic
or
Node.
These policies tell the compiler
where to
look for
moduleA
If they fail and if the module name is non-relative
"moduleA"
the compiler attempts to
locate an external module declaration.
We'll talk about non-relative imports next.
Finally, if the compiler still can't parse the module, it logs an error.
In this case, the error
error TS2307: Cannot find module 'moduleA'.
Depending on whether the module reference is relative or non-relative, the module import resolves in different ways.
Relative imports
are
/
, .
./
or
../
At the beginning.
Here are some examples:
import Entry from "./components/Entry";
import { DefaultHeaders } from "../constants/http";
import "/mod";
All other forms of import are treated as non-relative. Here are some examples:
import * as $ from "jQuery";
import { Component } from "angular2/core";
Relative import resolution comes relative to the file that imported it, and cannot be resolved to an external module declaration. You should use relative imports for your own modules to ensure their relative position at runtime.
There are two module resolution strategies available:
Node
and
Classic.
Y
ou can
--moduleResolution
to specify which one to use.
The default is
Node.
This policy was previously the default resolution policy for TypeScript. Now, it exists primarily for backward compatibility.
The relatively imported module is parsed relative to the file in which it was imported.
So the
import { b } from "./moduleB"
in
/root/src/folder/A.ts
uses the following lookup process:
/root/src/folder/moduleB.ts
/root/src/folder/moduleB.d.ts
For imports of non-relative modules, the compiler traverses the parent directory in turn from the directory that contains the imported files, trying to locate the matching claims file.
Like what:
There is a non-relative import import for
moduleB
import { b } from "moduleB"
which
/root/src/folder/A.ts
and is
"moduleB"
/root/src/folder/moduleB.ts
/root/src/folder/moduleB.d.ts
/root/src/moduleB.ts
/root/src/moduleB.d.ts
/root/moduleB.ts
/root/moduleB.d.ts
/moduleB.ts
/moduleB.d.ts
This parsing strategy attempts to mimic the Node .js module resolution mechanism at runtime. The complete Node .js algorithm can be found .js node module documentation.
In order to understand the parsing steps followed by TypeScript compilation, it is important to understand .js module first. T
ypically, imports in .js are made
require
function call.
Node .js behave differently
require
on whether the require is a relative path or a non-relative path.
The relative path is simple. F
or example, suppose you have a file path
/root/src/moduleA.js
that contains an import var x s
var x = require("./moduleB");
Node .js this import in the following order:
Treat
/root/src/moduleB.js
to check for the existence.
Treat
/root/src/moduleB
directory to check if it
package.json
file and it
"main"
module.
In our case, if Node.js discovers a file
/root/src/moduleB/package.json
contains the
{ "main": "lib/mainModule.js" }
then Node.js
/root/src/moduleB/lib/mainModule.js
Treat
/root/src/moduleB
a directory and check to see if it
index.js
file.
This file is implicitly used as the "main" module under that folder.
You can read .js documentation for more details: file modules and folder modules.
However,
the resolution of non-relative
module names is a completely different process. N
ode will find your module
node_modules
in a special folder.
node_modules
be in the same directory as the current file, or in the upper directory.
Node traverses the parent directory, looking for
node_modules
it finds the module to load.
Or use the example above, but assume
/root/src/moduleA.js
is using a non-relative path to import var x s
var x = require("moduleB");
。
Node resolves
moduleB
in the following order until there is a match.
/root/src/node_modules/moduleB.js
/root/src/node_modules/moduleB/package.json
(if the
"main"
/root/src/node_modules/moduleB/index.js
/root/node_modules/moduleB.js
/root/node_modules/moduleB/package.json
(if the
"main"
/root/node_modules/moduleB/index.js
/node_modules/moduleB.js
/node_modules/moduleB/package.json
the
"main"
/node_modules/moduleB/index.js
Note that .js in steps (4) and (7) will jump up the level directory.
You can read .js Documentation for more details:
loading modules
node_modules
TypeScript is an analysis strategy .js mode runtime to locate module definition files during the compilation phase. T
herefore, TypeScript adds the extensions of the TypeScript source files
.ts
.tsx
and
.d.ts
Node resolution logic.
At the same time, TypeScript uses the field
"typings"
package.json
to represent a meaning similar
"main"
- the compiler uses it to find the "main" definition file to use.
For example, there is an import
import { b } from "./moduleB"
/root/src/moduleA.ts
is
"./moduleB"
/root/src/moduleB.ts
/root/src/moduleB.tsx
/root/src/moduleB.d.ts
/root/src/moduleB/package.json
the
"typings"
/root/src/moduleB/index.ts
/root/src/moduleB/index.tsx
/root/src/moduleB/index.d.ts
Recall that Node .js find
moduleB.js
file, then
package.json
and
index.js
Similarly, a non-relative import follows the resolution logic .js Node, first finding the file and then the appropriate folder.
/src/moduleA.ts
import { b } from "moduleB"
in the following search order:
/root/src/node_modules/moduleB.ts
/root/src/node_modules/moduleB.tsx
/root/src/node_modules/moduleB.d.ts
/root/src/node_modules/moduleB/package.json
(if the
"typings"
/root/src/node_modules/moduleB/index.ts
/root/src/node_modules/moduleB/index.tsx
/root/src/node_modules/moduleB/index.d.ts
/root/node_modules/moduleB.ts
/root/node_modules/moduleB.tsx
/root/node_modules/moduleB.d.ts
/root/node_modules/moduleB/package.json
(if the
"typings"
/root/node_modules/moduleB/index.ts
/root/node_modules/moduleB/index.tsx
/root/node_modules/moduleB/index.d.ts
/node_modules/moduleB.ts
/node_modules/moduleB.tsx
/node_modules/moduleB.d.ts
/node_modules/moduleB/package.json
(if the
"typings"
/node_modules/moduleB/index.ts
/node_modules/moduleB/index.tsx
/node_modules/moduleB/index.d.ts
Don't be intimidated by the number of steps here - TypeScript just jumps up the catalog twice in steps (8) and (15). This is no more complicated .js in The Node.
--noResolve
Normally, the compiler resolves the module import before it starts compiling.
Whenever it successfully parses import on
import
file, the file is added to a list of files for later processing by the compiler.
--noResolve
tells the compiler not to add any files that are not uploaded on the command line to the compilation list.
The compiler will still try to parse the module, but as long as the file is not specified, it will not be included.
Like what
import * as A from "moduleA" // OK, moduleA passed on the command-line
import * as B from "moduleB" // Error TS2307: Cannot find module 'moduleB'.
tsc app.ts moduleA.ts --noResolve
Compile
app.ts
with
--noResolve
moduleA
because it is specified on the command line.
moduleB
found because it was not passed on the command line.
exclude
in the exclude list still used by the compiler?
tsconfig.json
the folder into an "engineering" if
“exclude”
“files”
tsconfig.json
and all subdirectdirecters are in the compilation list.
If you want to exclude some files with
“exclude”
or even if you want to specify a list of all the files to compile,
“files”
Some are
tsconfig.json
I
t does not involve module resolution discussed above.
If the compiler recognizes that a file is a module import target, it is added to the compilation list, regardless of whether it is excluded or not.
Therefore, to exclude a file from the compilation list, you need to exclude it from all files that
import
it or that use
/// <reference path="..." />
instruction.