ZetCode

TypeScript Setup

last modified October 15, 2026

TypeScript code cannot be executed directly by browsers or by most JavaScript runtimes. It is first checked for type errors and then turned into plain JavaScript. This tutorial shows how to install the TypeScript compiler, how to compile and run TypeScript programs, and how to configure a project with the tsconfig.json file.

Installing TypeScript

TypeScript is distributed as an npm package. It requires Node.js, which also provides the npm and npx tools. The recommended way is to install TypeScript locally in each project, so that every project uses a known compiler version.

$ mkdir ts-project
$ cd ts-project
$ npm init -y
$ npm install --save-dev typescript

The npm init -y command creates a package.json file. The --save-dev option records TypeScript as a development dependency; it is only needed to build the project, not to run the compiled JavaScript.

$ npx tsc --version
Version 5.9.3

The compiler is called tsc. The npx tool runs the locally installed version from the node_modules directory.

Compiling a program

We create a small program and compile it with tsc.

hello.ts
function greet(name: string): string {
    return `Hello, ${name}!`;
}

console.log(greet("TypeScript"));

The greet function takes a string and returns a string. The type annotations exist only at compile time.

$ npx tsc hello.ts
$ node hello.js
Hello, TypeScript!

The compiler creates the hello.js file next to the source file. The JavaScript file has the type annotations removed and can be run with Node.js.

Type errors

The main job of the compiler is to find type errors before the code runs.

errors.ts
function area(width: number, height: number): number {
    return width * height;
}

console.log(area(4, "5"));

The second argument is a string, but the function expects a number.

$ npx tsc errors.ts
errors.ts(5,21): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
$ node errors.js
20

The compiler reports the error with the file name, line, and column. Note that by default it still writes the errors.js file. The JavaScript runtime silently converts "5" to a number and prints 20; in other cases such a bug would surface much later. With the --noEmitOnError option, no JavaScript is produced when there are errors.

$ npx tsc --noEmitOnError errors.ts
errors.ts(5,21): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.

Running TypeScript directly

Compiling to a separate file is not always needed. The tsx tool compiles and runs a TypeScript file in one step. It can be added as a development dependency, or npx offers to download it on first use.

$ npm install --save-dev tsx
$ npx tsx hello.ts
Hello, TypeScript!

The tsx tool only removes the types; it does not check them. The examples in the ZetCode TypeScript tutorials show their output with npx tsx.

Recent Node.js versions (22.18 and later, 23.6 and later) can run TypeScript files directly by stripping the type annotations.

$ node hello.ts
Hello, TypeScript!

This works only for TypeScript syntax that can be erased. Features that generate JavaScript code, such as enums or namespaces, are rejected.

colors.ts
enum Color {
    Red,
    Green,
}

console.log(Color.Green);

An enum is not just a type annotation: it compiles to a JavaScript object. Node.js only removes types and does not generate code, so it stops with an error.

$ node colors.ts
...
SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript enum is not supported in strip-only mode

Node.js also does not rewrite import paths, so in projects with several files the compiler or tsx is the more practical choice. Since TypeScript 5.8, the erasableSyntaxOnly compiler option reports the features that Node.js cannot strip.

The tsconfig.json file

A project is configured with the tsconfig.json file. The npx tsc --init command creates one with a set of recommended options and comments. The following configuration is a simple starting point for a Node.js project.

tsconfig.json
{
  "compilerOptions": {
    "target": "es2022",
    "module": "nodenext",
    "rootDir": "src",
    "outDir": "dist",
    "strict": true,
    "sourceMap": true,
    "skipLibCheck": true
  },
  "include": ["src"]
}

The target option sets the JavaScript version of the output; es2022 is supported by all current Node.js versions and browsers. The module option set to nodenext follows the module rules of Node.js. The source files are taken from the src directory and the compiled files are written to dist. The strict option enables strict type checking, sourceMap generates source maps for debugging, and skipLibCheck skips checking of the declaration files of libraries, which speeds up compilation.

When tsc is run without file names, it reads tsconfig.json and compiles the whole project. When file names are given on the command line, the configuration file is ignored.

A project with modules

We create a project with two source files in the src directory.

src/utils.ts
export function formatPrice(amount: number, currency: string = "EUR"): string {
    return `${amount.toFixed(2)} ${currency}`;
}

The utils.ts module exports the formatPrice function.

src/main.ts
import { formatPrice } from "./utils.js";

const prices: number[] = [12.5, 7, 3.25];
const total = prices.reduce((sum, price) => sum + price, 0);

console.log(`Items: ${prices.length}`);
console.log(`Total: ${formatPrice(total)}`);

The main module imports the function. With the nodenext module setting, relative imports use the .js extension of the compiled file, even though the source file is utils.ts. The project also needs "type": "module" in package.json, so that Node.js treats the output as ES modules.

$ npm pkg set type=module
$ npx tsc
$ ls dist
main.js  main.js.map  utils.js  utils.js.map
$ node dist/main.js
Items: 3
Total: 22.75 EUR

The compiler writes the JavaScript files and source maps into the dist directory.

Strict mode

The strict option turns on a group of checks, including noImplicitAny, strictNullChecks, strictFunctionTypes, strictPropertyInitialization, and useUnknownInCatchVariables. It is enabled by tsc --init and should be used in all new projects.

strict.ts
function shout(text) {
    return text.toUpperCase();
}

const names: string[] = ["Alice", "Bob"];
const found = names.find(n => n.startsWith("C"));

console.log(found.length);

Without strict mode, this code compiles without errors, although the last line crashes at runtime because find returns undefined.

$ npx tsc --noEmit --target es2022 strict.ts
$ npx tsc --noEmit --target es2022 --strict strict.ts
strict.ts(1,16): error TS7006: Parameter 'text' implicitly has an 'any' type.
strict.ts(8,13): error TS18048: 'found' is possibly 'undefined'.

In strict mode, the compiler requires a type for the text parameter and reports that found may be undefined. The --noEmit option only checks the code without writing any files.

Watch mode and npm scripts

In watch mode, the compiler stays running and recompiles the project whenever a source file changes.

$ npx tsc --watch

The common commands are usually stored as scripts in package.json.

package.json
{
  "type": "module",
  "scripts": {
    "build": "tsc",
    "check": "tsc --noEmit",
    "start": "node dist/main.js",
    "dev": "tsx src/main.ts"
  },
  "devDependencies": {
    "tsx": "^4.23.0",
    "typescript": "^5.9.3"
  }
}

The project is then built with npm run build and started with npm start. During development, npm run dev runs the source directly and npm run check performs the type checking that tsx skips.

Type definitions for Node.js

Type information for the Node.js API, such as the fs or process modules, is not part of TypeScript. It is provided by the @types/node package.

$ npm install --save-dev @types/node

Many other libraries ship their own type definitions; for the rest, packages are available under the @types scope.

Best Practices

Source

What is a tsconfig.json

This tutorial showed how to install TypeScript, compile and run TypeScript code, and configure a project with tsconfig.json.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all TypeScript tutorials.