Chapter 01
Hello, TypeScript
Installing the toolchain, creating your first project, and understanding how TypeScript compiles to JavaScript.
Installing the Toolchain
TypeScript runs on Node.js. You need two things: the Node.js runtime (which includes npm, the package manager) and the TypeScript compiler (tsc). We'll also install tsx, a tool that compiles and runs TypeScript files in one step - no separate build needed during development.
Install Node.js from nodejs.org (LTS version). Verify it's installed:
node --version # v22.x or later
npm --version # 10.x or laterNow create a project directory and initialize it:
mkdir chat-server
cd chat-server
npm init -ynpm init -y creates a package.json with defaults. This is your project manifest - it tracks dependencies, scripts, and metadata. Every npm command reads it.
Install TypeScript and tsx as dev dependencies:
npm install --save-dev typescript tsx @types/nodeThree packages:
typescript- the compiler (tsc). Checks types and compiles.tsfiles to.js.tsx- runs TypeScript directly. No compile step needed during development: one command takes you from source to running program.@types/node- type definitions for Node.js APIs (filesystem, networking, etc.). Without these, TypeScript doesn't know aboutprocess,Buffer, or any Node.js built-ins.
@types/node is necessary but not sufficient. Current TypeScript does not pick the package up automatically - you must also list it in tsconfig.json under "types": ["node"], which we do below. Skip that and process fails to compile with TS2591: Cannot find name 'process' even though the types are sitting in node_modules.--save-dev (or -D) installs packages as development dependencies. They're needed for building but not for running in production. The compiled JavaScript doesn't need the TypeScript compiler.Understanding tsconfig.json
Create a tsconfig.json - the TypeScript compiler configuration. This file controls how TypeScript checks and compiles your code:
npx tsc --initThis generates a tsconfig.json with many commented-out options. Here's what matters for our project:
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"strict": true,
"types": ["node"],
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"outDir": "dist",
"rootDir": "src",
"declaration": true
},
"include": ["src/**/*"]
}Key settings:
target: "ES2022"- compile to modern JavaScript. Determines which JS features are available in the output.module: "Node16"- use Node.js's module system. Supports both CommonJS (require) and ES modules (import).strict: true- enables all strict type checking. This is the most important setting. It catches bugs that loose mode ignores: implicitany, null safety, and more. Always keep this on.types: ["node"]- loads the Node.js global declarations from@types/node. Without this,process,Buffer, andsetTimeoutare unknown to the compiler even though the package is installed, and any use of them fails withTS2591: Cannot find name 'process'. You don't need it for the first program, but every chapter from Chapter 5 onward touches Node's built-ins.outDir: "dist"- compiled JavaScript goes here. Source TypeScript stays insrc/.rootDir: "src"- tells the compiler where to find source files. The directory structure undersrc/is mirrored indist/.
strict. It's the reason TypeScript exists. Without strict mode, TypeScript is just JavaScript with optional annotations - you lose most of the safety guarantees. Every example in this guide assumes strict mode is on.Your First Program
Create a src directory and your first TypeScript file:
mkdir srcconst name: string = "TypeScript";
const port: number = 8080;
console.log(`Starting chat server...`);
console.log(`Server: ${name} on port ${port}`);A few things to notice:
const name: string- a type annotation. The: stringafter the variable name declares its type. TypeScript checks that only strings are assigned to it.const port: number- numbers in TypeScript are always 64-bit floats, exactly as in JavaScript. There is one numeric type: no separate integer and float types, and no fixed widths to choose between.- `
Template ${literals}- backtick strings with${expr}interpolation. Any expression inside${}` is evaluated and spliced into the string. console.log- prints a line to stdout.
Compiling and Running
There are two ways to run TypeScript: compile first then run the JavaScript, or use tsx to do both at once.
Option 1: tsx (development)
npx tsx src/index.tstsx compiles and runs in one step. No dist/ directory created. This is what you use during development - fast feedback, no build step.
Option 2: tsc + node (production)
npx tsc
node dist/index.jstsc compiles all .ts files in src/ to .js files in dist/. Then node runs the JavaScript. This is what you use for production - the compiled JS doesn't need TypeScript at runtime.
A Tour of Commands
Add these scripts to package.json:
package.json (scripts section)
{
"scripts": {
"dev": "tsx watch src/index.ts",
"build": "tsc",
"start": "node dist/index.js",
"typecheck": "tsc --noEmit"
}
}npm run dev
Runs with tsx watch - compiles, runs, and watches for changes. Every time you save a file, it restarts automatically. Your main development loop.
npm run build
Compiles TypeScript to JavaScript in dist/. Type checks everything. Fails if there are type errors.
npm start
Runs the compiled JavaScript. For production - no TypeScript tooling needed at runtime.
npm run typecheck
Type-checks without producing output (--noEmit). The fast way to verify your code has no type errors - ideal in CI or a pre-commit hook.
Project Structure
Here's what your project looks like now:
chat-server/
├── package.json ← project manifest: dependencies and scripts
├── package-lock.json ← exact dependency versions, commit this
├── tsconfig.json ← TypeScript compiler config
├── node_modules/ ← installed dependencies (auto-managed by npm)
├── src/
│ └── index.ts ← your TypeScript source code
└── dist/ ← compiled JavaScript (created by tsc)node_modules/ and dist/ to your .gitignore. node_modules is recreated by npm install. dist is recreated by npm run build. Neither belongs in version control.Exercise
- Run
npx tsx src/index.tsand verify you see the output. - Run
npx tscand find the compiled JavaScript indist/index.js. Open it - notice the type annotations are gone. Run it withnode dist/index.js. - Try assigning a number to the
namevariable. Read the compiler error - TypeScript tells you exactly what's wrong. - Run
npm run typecheckto verify your code without compiling. Try introducing a type error and see it caught. - Set up
npm run devwithtsx watch. Edit your file and watch it restart automatically.
What's Next
You have a working TypeScript project with a compiler, a runner, and a type checker. The toolchain is in place and you know how to build, run, and check code.
In the next chapter, we'll cover the language fundamentals - variables, types, functions, and control flow - the building blocks you'll need before we start writing any networking code.