← back to section

TypeScript is not a standalone runtime. Browsers and servers execute plain JavaScript; TypeScript adds a type layer and a compiler on top. To get started you need a small set of tools: a runtime, a package manager, a compiler, and its configuration. Let's go through each one.

Node — the runtime

Node.js is the environment that runs JavaScript outside the browser, on a server. When you write a backend in TypeScript, Node is ultimately what executes the code.

Node versions are numbered with even LTS (Long Term Support) releases: 18, 20, 22. For a new project, pick the current LTS — at the time of writing that is Node 20. Even versions are stable and supported for years; odd versions are experimental and not used in production.

Check the installed version:

node --version   # v20.x.x

Node can run a file directly, but only if it is already JavaScript:

node app.js

A .ts file is not understood by Node out of the box — it must first be compiled, or run through a special loader (more on that below).

To avoid being tied to one Node version on a machine, it is convenient to install a version manager — nvm (or fnm). It lets you keep multiple versions and switch between projects.

npm and pnpm — package managers

Every real project depends on third-party libraries. npm (Node Package Manager) is the tool built into Node that downloads and stores them. The list of dependencies and project commands is described in a package.json file.

Initialise a new project:

npm init -y          # creates package.json with default values
npm install express  # installs the library and records it in package.json

Installed packages go into a node_modules/ folder (which is not committed to git), and exact versions are pinned in package-lock.json — so that everyone on the team gets the same packages.

pnpm is an alternative manager, command-compatible with npm, but storing packages more efficiently: a shared cache across the whole machine instead of a copy in each project. On large projects it noticeably saves disk space and installation time.

pnpm install        # same as npm install, but faster and more compact
pnpm add express

The commands are nearly identical: install, add, remove. The choice between them is a team preference; starting with npm is fine since it already comes with Node.

Project scripts are described in the scripts section of package.json and run via npm run:

{
  "scripts": {
    "build": "tsc",
    "start": "node dist/app.js"
  }
}
npm run build   # runs tsc

tsc — the TypeScript compiler

tsc (TypeScript Compiler) is the program that takes your .ts files, checks types, and turns the code into plain JavaScript that Node can execute. TypeScript itself is installed as a development dependency:

npm install --save-dev typescript   # -D is the short form
npx tsc --version                    # 5.x.x

The --save-dev (-D) flag means the package is needed only during development, not while the application is running. npx runs the locally installed version from node_modules.

Compile a single file:

npx tsc app.ts   # produces app.js alongside it

In practice, files are not compiled one at a time — the full project configuration lives in a separate file.

tsconfig.json — compiler configuration

tsconfig.json describes exactly how to compile the project: which files to include, which JavaScript version to target, and how strictly to check types. Generate a starter file with:

npx tsc --init

The file is large, but on the first day only a few key options matter:

{
  "compilerOptions": {
    "target": "ES2022",        // which JS version to compile to
    "module": "NodeNext",      // how imports/exports are described
    "strict": true,            // enable all strict type checks
    "outDir": "dist",          // where to put the output
    "rootDir": "src"           // where the sources live
  }
}

The main ones:

  • target — the JavaScript version in the output. ES2022 suits Node 20 well: modern syntax without unnecessary compatibility with older browsers.
  • module — how modules (imports and exports) are organised. For a Node backend the current value is NodeNext.
  • strict — the most important option. It enables a bundle of strict checks at once (no implicit any, control of null and undefined, and others). Short formula: always start a new project with strict: true — otherwise you lose half the benefit of TypeScript.

After configuration, a single command without arguments is enough — tsc finds tsconfig.json on its own and builds the whole project:

npx tsc

ts-node and tsx — running without a separate build step

Compiling the whole project just to test a small change is slow. During development it is more convenient to run .ts files directly.

ts-node and tsx are tools that compile TypeScript on the fly and immediately execute it in Node, without manually invoking tsc. tsx is newer and faster, and easier to set up:

npm install -D tsx
npx tsx src/app.ts        # runs the TypeScript file immediately
npx tsx watch src/app.ts  # restarts on every file change

The important distinction: tsx is for development (quick run and check), tsc is for building the release version into dist/, which plain Node then executes. Many teams use tsx locally only, while the type check in the build is still done via tsc.

TypeScript project structure

A typical minimal project looks like this:

my-app/
├── src/             # .ts source files
│   └── app.ts
├── dist/            # compiled output (in .gitignore)
├── node_modules/    # dependencies (in .gitignore)
├── package.json     # dependencies and scripts
├── package-lock.json
└── tsconfig.json    # compiler configuration

The logic is simple: you write in src/, the compiler puts the compiled JavaScript in dist/, Node runs what is in dist/. The dist/ and node_modules/ folders are restored by the build and install commands, so they are not kept in git.

Linters and formatters

Once the foundation is set up, two code quality tools are added — not strictly required, but present in almost every real project.

  • ESLint — a linter: finds suspicious places and rule violations (unused variables, dangerous patterns). It analyses the code and suggests what to rewrite.
  • Prettier — a formatter: automatically brings code to a consistent style (indentation, quotes, line breaks). It does not look for bugs; it tidies up the formatting.

The roles do not overlap: ESLint is responsible for "what was written, semantically"; Prettier for "how it looks". They are usually configured together and connected to the editor so that formatting and checks fire on file save.

In short

  • Node is the environment that runs JavaScript on the server; use the current LTS (Node 20). It cannot run .ts files directly.
  • npm (built-in) and pnpm (faster, more compact) install dependencies; the list and scripts live in package.json.
  • tsc compiles .ts to .js with type checking; configuration lives in tsconfig.json.
  • Key tsconfig options: target (JS version), module (NodeNext for Node), strict (always enable).
  • tsx runs TypeScript on the fly for development; tsc builds the release into dist/.
  • Structure: sources in src/, output in dist/, dependencies in node_modules/ (last two in .gitignore).
  • ESLint catches semantic issues; Prettier formats style — different jobs, used together.
  • Modules and npm — how imports, exports, and package management work.
  • Type basics — what the compiler actually checks, and why strict matters.
  • JavaScript essentials for TypeScript — the language foundation TypeScript is built on.