A TypeScript Project Structure Guide
By: Bing Ren
Tags: Typescript, Coding, JavaScript, Programming, Web Development

General tsconfig.json Options

Option “extends”

Option “extends” specifies another configuration file to inherit from, and may probably be a good starting point of your configuration. There are community maintained base configurations tuned to particular runtime environments that you can install and inherit in your projects. See project @tsconfig/bases.

Option “rootDir”

“rootDir” specifies the root that is expected to contain all Implementation Files. “rootDir” is expected to contain all Implementation Files, i.e. source files that will be compiled.

By default “rootDir” is inferred as “the longest common path of all non-declaration input files”. This means if all your input source files are under “./src”, “./src” is inferred as the “rootDir”. If your source files are under both “./src” and “./test”, then “./” would be the “rootDir”.

Don’t confuse “rootDir” with “rootDirs”. They are different.

Output Options

These options set what the emitted JavaScript is like (so that they are compatible with different runtime environments), what other products are produced, and where are they outputted.

Option “outDir”

If specified, the output .js (as well as .d.ts , .js.map , etc.) files will be emitted into this directory. In most TypeScript projects, “outDir” should be set. Otherwise, outputs will be emitted besides the sources, polluting the source folders.

The directory structure under “rootDir” will be preserved in “outDir”. That means the JavaScript compiled from “rootDir/pathA/pathB/moduleC.ts” will be emitted to “outDir/pathA/pathB/moduleC.js”.

Altogether, the rules are: “rootDir” contains all Implementation Files to be compiled, and “outDir” is where the outputs are emitted. The same directory structure under “rootDir” is preserved in “outDir”. Some options discussed in this article allow a very flexible directory structure. However, under no circumstance this rule changes.

Option “target”

Meant to be set according to the runtime environment that the emitted JS code will be executed in. This option determines what features in the emitted JS are downleveled, i.e. what features implemented in a newer version of the Javascript language should not be emitted in the output Javascript file, but rather be implemented with the syntax and features of an older version, so as to be compatible with an older runtime.

Option “target” changes the default values of options “lib”, “module”, and through option “module”, option “moduleResolution”. This means if “target” is set correctly, these options may probably be left to use the default values.

Option “module”

This option determines the module import & export codes in the emitted JavaScript. It affects the emitted JavaScript at runtime, not the module resolution of TypeScript at compile time. The default value depends on the option “target”. “CommonJS” is what you very likely want.

Option “declaration”

If this option is set to “true”, the compiler generates type declaration “.d.ts” files. If the project is to be used by other codes, this option should be turned on.

Option “declarationMap”

If “declaration” is turned on, option “declarationMap” makes the compiler emit source maps for the type declarations (.d.ts), mapping definitions back to the original “.ts” source files. The effect is when the user clicks a definition, editors (such as VS Code) can go to the original .ts file when using features like “Go to Definition”.

“package.json” Options

These options define the exposed interface of the package through exports of types, functions, values, objects, as well as the entry point that is executed when the package is imported.

Option “types”, “typings”

Indicates the package’s type declaration file (.d.ts). “typings” is synonymous with “types” and both can be used. If “index.d.ts” lives at the root of the package, “types” can be omitted, although still recommended.

If the package is to be used by external codes, “types” should be indicated.

Option “main”

This is the primary JavaScript entry point to the package.

Commonly, “types” points to the declaration file, and “main” points to the .js emitted from the TypeScript entry point in the “outDir”.

Option “exports”

As an alternative to the “main” option, this option supports subpath exports and conditional exports. As of today under Node.js v15.0.1, both features are still experimental, therefore will not be further discussed.