This article's content
TypeScript installation and configuration

Installing TypeScript

yarn add --dev typescript
npm i typescript --save-dev

Now you can use the TypeScript compiler running tsc. To test whether a TypeScript file compiles create a simple file:

const name = "Mathias";
console.log(name);

and then run tsc index.ts.

You thought it was as simple as that but you end up with an error:

.../node_modules/typescript/lib/lib.dom.d.ts:19620:15
    19620 declare const name: void;
                        ~~~~
    'name' was also declared here.

The reason is that name is already defined on the window object (global scope), so you either have to change your variable name or preferably make your file a module by adding export{} to compile without errors:

const name = "Mathias";
console.log(name);
export {}

Now it works. Let’s create another module other.ts and import it into index.ts to see how the compiler behaves. Will it compile all TS files to one single JS file or into two JS files?

import sayHello from "./other";

const name = 'Mathias';
console.log(sayHello(name));

export {};
function sayHello(name: string) {
    console.log(`Hello ${name}`);
}

export default sayHello;

Executing tsc .\src\index.ts shows that TypeScript creates two js files, index.js and other.js.

Can I bundle my TS files into one JS file?

It is okay to compile many TS files into many JS files for a NodeJS project, but for a web front-end project we would rather like to have a single bundled file that we could load in the browser. Can that be done with TypeScript only? Yes, but with restrictions: You can use the compilerOption outFile to concatenate and emit output to a single file, but outFile cannot be used unless module is None, System, or AMD. That means, that this option cannot be used to bundle CommonJS or ES6 modules. For that to work, we need a bundler like Webpack.

How can I compile my TS files without specifying everything on the command line?

It is impractical to run tsc index.ts every time we change code. We could use TypeScript’s watch mode with tsc -w index.ts instead, but there is a better way. We define all our compile options once in a tsconfig.json and from now on simply run tsc or tsc -w without specifying any other parameters.

Configuring TypeScript using tsconfig.json

Run tsc --init to create a tsconfig.json in your project root. Inspecting the file, you can see that there are many options, most of them commented out.

How should I adjust tsconfig.json?

Here are just a few of the more important config properties:

  • You want all your TS files within src folder compiled? Add the include property
  • You want compilation output to a specific folder? Use outDir compiler option
  • You want to generate sourceMap files for better debugging? Use sourceMap: true
  • In some places, TypeScript doesn’t try to infer any types for us and instead falls back to the most lenient type called any. This defeats the purpose of using TypeScript in the first place, so you should set noImplicitAny: true.
  • strictNullChecks: true makes handling null and undefined more explicit, and spares us from worrying about whether we forgot to handle null and undefined

Here is an example config file:

{
    "compilerOptions": {
        "module": "commonjs",
        "esModuleInterop": true,
        "target": "es6",
        "noImplicitAny": true,
        "moduleResolution": "node",
        "sourceMap": true,
        "outDir": "dist",
        "baseUrl": ".",
        "paths": {
            "*": [
                "node_modules/*",
                "src/types/*"
            ]
        }
    },
    "include": [
        "src/**/*"
    ]
}
// src/index.ts
const name = "Mathias";
console.log(name);
export {}

Now, when running tsc in your project root folder, your ts files under /src will be compiled into a /dist folder, including source maps. You can run tsc -w to watch for file changes and automatically compile changed files.

Option to use import type

With the following option any import that is just a type will be imported as import type instead of import. This also works with auto import of IDEs.

"compilerOptions": {
  "importsNotUsedAsValues":"error",
  // ...
}

About Author

Mathias Bothe To my job profile

I am Mathias, born 40 years ago in Heidelberg, Germany. Today I am living in Munich and Stockholm. I am a passionate IT freelancer with more than 16 years experience in programming, especially in developing web based applications for companies that range from small startups to the big players out there. I am founder of bosy.com, creator of the security service platform BosyProtect© and initiator of several other software projects.