Before the advent of ES2015, JavaScript did not have a native module system (ES Module) and had to resort to third-party RequireJS and SystemJS to use the module functionality.

A module is essentially a JS/TS file, similar to a sandbox environment, that uses import statements to introduce the APIs and values of other modules, and export statements to expose its own APIs and values.

TypeScript natively supports the syntax of ES Modules, and can use import and export statements in .ts files. By default, TypeScript only supports the introduction of .ts and .d.ts file modules, and TypeScirpt can be made to support .js files by modifying the allowJS configuration option.

I. The way to import modules

1
2
3
// example.ts
import "../program";
import "package";

The above code is the two ways of importing modules to be introduced.

  • Path : import module by module (file) path, either relative path or absolute path
  • module name (package name) : import module by module name (package name).

The first way is simpler, typescript will look for the file (program.ts or program.d.ts) according to the file path we specified. In the above example, typescript will look for program.ts in the parent directory of the current file first, and if program.ts is not found, then If program.d.ts is not found, it will then look for program.d.ts and if it finds it, it will import the found module.

The second way, introducing by package name, is more complicated and will be highlighted next.

II. Module positioning strategy

The second example above import "package"; , imports a module by module name. When typescirpt handles this import statement, it uses one of the following two module positioning strategies.

  • Classic module positioning strategy : A strategy invented for compatibility with older versions.
  • Node module positioning strategy : The default strategy.

TypeScript’s module positioning strategy is configurable, either through the -moduleResolution option of tsc or through the -moduleResolution compilation option.

Classic module positioning strategy

Using the Classic module location strategy, TypeScirpt first looks for a .ts file or .d.ts file with the same name as the module in the same directory as the current file, and if it is not found, it looks for it in the next directory until it is found or it reaches the root of the disk and is not found, and if it is found, it introduces the found module.

Take the above example import "package"; as an example. Suppose the example.ts file path is D:\program\src\example.ts. First look for the package.ts and package.ds files in D:\program\src\, the same level as the example.ts file, and if you don’t find them, keep looking for the package.ts and package.ds files in the parent directory D:\program\, and if you don’t find them Keep looking upwards in the root directory D:\\ on the D drive, and if you find it, introduce the module.

Node Module Resolution Policy

Node Module Resolution is the default positioning strategy for TypeScript, and is the most commonly used module positioning strategy.

Any JS programmer will know that projects have a node_modules folder, which holds some public packages for use in the project. To understand how typeScript makes use of the Node module location strategy, let’s first look at how Nodejs locates modules.

The Node module location strategy can be a bit complicated for non-Node.js programmers. It’s the same as the Classic module location strategy, which starts by traversing up through folders to find modules, but it’s also a little different.

As an example, take the following example.

1
2
3
// D:\code\src\example.ts
import '../program';
import 'package';

The first import statement, import module using relative path, in this case, first look for program.ts and program.d.ts files in the parent directory, if not found, then check if there is a program folder in the parent directory, if D:\code\src\program exists, and if a package.json file exists in this D:\code\src\program\ directory, then it will import the file with the path specified by the types and typings fields in package.json.

If the package.json file does not exist in the D:\code\src\program\ directory, or if it is missing the types field, then it will check if the index.ts and index.d.ts files exist in that directory, and if it finds them, it will import the module, otherwise it will report an error.

The whole process is as follows.

1
2
3
4
5
6
7
1. ../program.ts
2. ../program.d.ts
3. ../program/package.json -> [[types]] -> file path
4. ../program/index.ts
5. ../program/index.d.ts

6. Error: Cannot find module

For the second import statement, importing modules using package names, the situation gets more complicated. First, it first looks for the node_modules folder in the current directory D:\code\src, and then looks for the module in the same way as the path import module.

If it doesn’t find the right file, it looks up (parent directory, traversing outwards) using the same logic. The whole process is as follows.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
Import statement: import 'package';
Import Location: D:\code\src\example.ts

1. D:/code/src/node_modules/package.ts
2. D:/code/src/node_modules/package.d.ts
3. D:/code/src/node_modules/package/package.json -> [[types]] ->
4. D:/code/src/node_modules/package/index.ts
5. D:/code/src/node_modules/package/index.d.ts

6. D:/code/node_modules/package.ts
7. D:/code/node_modules/package.d.ts
8. D:/code/node_modules/package/package.json -> [[types]] ->
9. D:/code/node_modules/package/index.ts
10. D:/code/node_modules/package/index.d.ts

11. D:/node_modules/package.ts
12. D:/node_modules/package.d.ts
13. D:/node_modules/package/package.json -> [[types]] ->
14. D:/node_modules/package/index.ts
15. D:/node_modules/package/index.d.ts

16. Error: Cannot find module

TypeScript using Node module location strategy

TypeScirpt uses Node module location strategy to import modules, when referring to relative paths of modules, is exactly the same, the difference is that when using package names to introduce modules, there is a little difference, it will check the node_modules/@types folder, the whole process is as follows.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Import statement: import 'package';
Import Location: D:\code\src\example.ts

1. D:/code/src/node_modules/package.ts
2. D:/code/src/node_modules/package.d.ts
3. D:/code/src/node_modules/package/package.json -> [[types]] ->
4. D:/code/src/node_modules/@types/moduleB.d.ts
5. D:/code/src/node_modules/@types/moduleB/index.d.ts (或者package.json文件指定的入口文件)
6. D:/code/src/node_modules/package/index.ts
7. D:/code/src/node_modules/package/index.d.ts

8. D:/code/node_modules/package.ts
9. D:/code/node_modules/package.d.ts
10. D:/code/node_modules/package/package.json -> [[types]] ->
11. D:/code/node_modules/@types/moduleB.d.ts
12. D:/code/node_modules/@types/moduleB/index.d.ts (或者package.json文件指定的入口文件)
13. D:/code/node_modules/package/index.ts
14. D:/code/node_modules/package/index.d.ts

15. D:/node_modules/package.ts
16. D:/node_modules/package.d.ts
17. D:/node_modules/package/package.json -> [[types]] ->
18. D:/node_modules/@types/moduleB.d.ts
19. D:/node_modules/@types/moduleB/index.d.ts (或者package.json文件指定的入口文件)
20. D:/node_modules/package/index.ts
21. D:/node_modules/package/index.d.ts

22. Error: Cannot find module