Setting Up TypeScript — tsconfig and Compiler

8 min read

You already have Node.js and VS Code installed from the JavaScript course. TypeScript installs on top of that — no new editor, no new runtime. This lesson takes you from an empty folder to a working tsc build, with a tsconfig.json you understand line by line. By the end you'll be able to compile and run TypeScript files on your own machine.

Installing TypeScript

TypeScript is just an npm package. Open a terminal in a fresh folder:

mkdir ts-for-qa
cd ts-for-qa
npm init -y
npm install typescript --save-dev
npx tsc --version

npm init -y creates a package.json with all the defaults. npm install typescript --save-dev adds TypeScript as a development dependency — it's a build-time tool, not something your tests need at runtime. npx tsc --version prints the installed compiler version (something like Version 5.4.3). If you see a version number, you're set.

A small but important detail: install TypeScript per-project, not globally. Different projects often pin different TypeScript versions, and a global install creates surprise mismatches. --save-dev keeps it scoped to this project.

The TypeScript compiler — tsc

tsc is the TypeScript compiler. Its job is simple: take .ts files in, produce .js files out. Along the way it checks types and refuses to emit if you have type errors (by default).

Try it without configuration. Create hello.ts:

const name: string = "QA";
console.log(`Hello, ${name}`);

Run:

npx tsc hello.ts

You'll see a new hello.js next to it — plain JavaScript with the type annotations stripped. Run that with Node.js:

node hello.js

Output: Hello, QA. That's the whole pipeline.

Creating tsconfig.json

Compiling files one at a time isn't realistic. A real project has dozens of .ts files, build options, output paths. tsconfig.json is where you tell tsc how to handle the project as a whole.

Generate a default one:

npx tsc --init

This creates a tsconfig.json at the project root with most options listed but commented out — it's a self-documenting starting point. The next section trims it down to a config a QA project actually wants.

The settings that matter

A few options pull most of the weight. The rest you can leave at defaults until a real need arises.

  • target — which version of JavaScript tsc compiles to. "ES2020" or "ES2022" are the right answers for any modern Node.js project (anything 18+). The compiler can use newer JavaScript features in your source code; this option controls what comes out the other side.
  • module — the module system. "commonjs" for plain Node.js scripts and most test frameworks. "ESNext" if your project uses ES modules (import/export with "type": "module" in package.json). When in doubt, "commonjs".
  • strict — enables all of TypeScript's strict-checking flags at once: noImplicitAny, strictNullChecks, strictFunctionTypes, and more. Always set this to true. Strict mode is the entire reason you're using TypeScript. Turning it off is like buying a seatbelt and refusing to wear it.
  • outDir — where compiled .js files go. "./dist" keeps build output separate from your .ts source.
  • rootDir — where your source .ts files live. "./src" is the convention.
  • esModuleInterop — set this to true. It smooths over historical compatibility quirks when importing CommonJS packages (most npm libraries) using ES module syntax (import x from "y").
  • resolveJsonModule — set this to true if you want to import fixture from "./fixture.json". Essential for test fixtures.

A minimal tsconfig.json for a QA project

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "strict": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "esModuleInterop": true,
    "resolveJsonModule": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

include tells the compiler which files belong to the project. exclude tells it what to ignore (you never want to type-check node_modules — it'd take forever and isn't your code).

With this config in place, you no longer pass filenames to tsc. You just run:

npx tsc

…and it compiles every .ts file under src/ into dist/. Or run it in watch mode and let it recompile on save:

npx tsc --watch

Watch mode is what you'll have running in a terminal tab while you work. Save a file, see compile errors instantly.

Skipping the build step with ts-node

For test scripts and quick utilities, the edit-compile-run cycle gets tedious. ts-node runs .ts files directly:

npm install ts-node --save-dev
npx ts-node src/hello.ts

It type-checks and executes in one step — no dist/ folder, no separate build. Most QA scripts you write while learning will run with ts-node. Production builds still use tsc because it's faster at scale and gives you a real .js artifact to ship.

The whole flow at a glance

Step 1 of 5

Write .ts file

Add type annotations in src/. VS Code shows red squiggles instantly when types don't match.

A note on Cypress and Playwright

Both frameworks ship with TypeScript support built in. You don't run tsc manually for test files — Cypress and Playwright handle compilation through their own pipelines (esbuild or swc under the hood). Your tsconfig.json still matters: both tools read it to honour your strict setting and module resolution. But the build-and-run step you just learned is for standalone scripts, page object helpers, and CI utilities — not the test files themselves.

⚠️ Common mistakes

  • Forgetting --save-dev. Installing TypeScript as a regular dependency (npm install typescript, no flag) ships the compiler in your production bundle. It still works, but it bloats deploys and confuses dependency audits. TypeScript is a development tool — keep it in devDependencies.
  • Disabling strict to make errors go away. When you turn on strict, an existing JavaScript-y codebase suddenly lights up red. The temptation is to set "strict": false and call it done. You've just removed every guarantee TypeScript was offering. Better: leave strict on and fix issues file by file (or use // @ts-expect-error sparingly with a TODO).
  • Mixing tsc output into source folders. If you don't set outDir, compiled .js files land next to your .ts files — and now your repo has login.ts AND login.js, both tracked, both confusing. Always set outDir: "./dist" and add dist/ to .gitignore.

🎯 Practice task

End-to-end TypeScript setup. 20-30 minutes including the install.

  1. Create a fresh folder ts-for-qa and cd into it.

  2. Run npm init -y then npm install typescript ts-node --save-dev.

  3. Run npx tsc --init to generate tsconfig.json. Open it in VS Code.

  4. Replace its contents with the minimal config from the lesson above (set outDir, rootDir, strict: true, etc.).

  5. Create a src/ folder and a file src/hello.ts:

    const tester: string = "QA Engineer";
    const yearsExperience: number = 2;
    console.log(`${tester}, ${yearsExperience} years in.`);
  6. Run npx tsc from the project root. Confirm a dist/hello.js appears.

  7. Run node dist/hello.js and check the output.

  8. Now try npx ts-node src/hello.ts — same output, no dist/ step.

  9. Stretch: introduce a deliberate type error — change the line to const tester: string = 42;. Run npx tsc and read the error message. Then revert and confirm it compiles cleanly. You've just experienced the core feedback loop you'll use every day.

Save this folder. The next lesson writes a real first TypeScript file inside it.

// tip to track lessons you complete and pick up where you left off across devices.