Why TypeScript?

TypeScript adds optional static typing to JavaScript. This means you catch bugs at compile time — before they reach your users — and get much better IDE support with autocomplete and inline documentation. The learning curve is gentler than it looks, especially if you already know JavaScript.

Setting Up TypeScript in 5 Minutes

  1. Install TypeScript globally or as a dev dependency:
    npm install --save-dev typescript ts-node
    npx tsc --init
  2. This creates a tsconfig.json. Key settings to know:
    {
      "compilerOptions": {
        "target": "ES2020",
        "module": "CommonJS",
        "strict": true,
        "outDir": "./dist",
        "rootDir": "./src"
      }
    }
  3. Rename your .js files to .ts and start the compiler watcher:
    npx tsc --watch

Core Concept 1: Basic Types

TypeScript's basic types mirror JavaScript primitives but are declared explicitly:

let username: string = "Alex";
let age: number = 30;
let isActive: boolean = true;
let scores: number[] = [90, 85, 78];
let anything: unknown = "could be anything";

Use unknown instead of any — it forces you to type-check before using the value, keeping your code safe.

Core Concept 2: Interfaces

Interfaces define the shape of an object. They're one of TypeScript's most useful features:

interface User {
  id: number;
  name: string;
  email: string;
  role?: 'admin' | 'editor' | 'viewer'; // optional field
}

function greetUser(user: User): string {
  return `Hello, ${user.name}!`;
}

The ? makes a field optional. The pipe | creates a union type — the value must be one of those strings.

Core Concept 3: Type Aliases

Type aliases are similar to interfaces but more flexible — they can represent primitives, unions, tuples, and more:

type Status = 'pending' | 'active' | 'archived';
type Coordinates = [number, number]; // tuple

const location: Coordinates = [48.8566, 2.3522];

Core Concept 4: Functions with Types

Always type your function parameters and return values:

function add(a: number, b: number): number {
  return a + b;
}

// Arrow function
const multiply = (a: number, b: number): number => a * b;

// Async function
async function fetchUser(id: number): Promise<User> {
  const res = await fetch(`/api/users/${id}`);
  return res.json();
}

Core Concept 5: Generics

Generics let you write reusable, type-safe functions without losing type information:

function getFirst<T>(arr: T[]): T | undefined {
  return arr[0];
}

getFirst([1, 2, 3]);       // returns number
getFirst(["a", "b", "c"]); // returns string

TypeScript in React

If you're using React, create your project with TypeScript from the start:

npm create vite@latest my-app -- --template react-ts

Type your component props with an interface:

interface ButtonProps {
  label: string;
  onClick: () => void;
  disabled?: boolean;
}

export function Button({ label, onClick, disabled = false }: ButtonProps) {
  return <button onClick={onClick} disabled={disabled}>{label}</button>;
}

Tips for the Transition

  • Enable "strict": true from day one — it catches the most bugs
  • Avoid any — use unknown when the type is truly dynamic
  • Let TypeScript infer types when possible; only annotate when needed
  • Use the VS Code TypeScript integration — hover over anything to see its inferred type

You Already Know Most of It

TypeScript is a superset of JavaScript — every valid JavaScript file is also a valid TypeScript file. The types you add are just annotations; at runtime, they're stripped out completely. Start small, add types incrementally, and you'll quickly see the payoff in fewer runtime errors and a much better development experience.