← Back to the Build Your Homepage series
🔷
EPISODE 01
Why TS · install · types · tsconfig · type · any · unknown · never · narrowing · interface · extends · structural typing · constructor · public/private · readonly · abstract

TypeScript Basics · Type Aliases & any/unknown/never · Interface vs Type Alias · Classes in TypeScript

Add static types to JavaScript with TypeScript. Set up tsc, learn the primitive types, type inference, and the most useful tsconfig flags. Name complex types with type aliases, understand any (escape hatch), unknown (safe any), and never (impossible). Learn type narrowing. When to use interface and when to use type. Learn extends, declaration merging, and how structural typing decides assignability. Use TypeScript's class features: access modifiers, parameter properties, readonly, and abstract classes for shared base behavior.

TypeScripttypestsconfigstricttypeanyunknownnevernarrowinginterfaceextendsstructuralclassconstructorprivatereadonlyabstract
Duration
⏱ About 2 hours + About 1.5 hours + About 1.5 hours + About 1.5 hours
Level
📊 Intermediate
Prerequisite
🎯 JavaScript track
OUTCOME
Convert a JS project to TS and run it with strict mode enabled / Choose the right escape hatch and narrow types correctly / Choose interface vs type consistently across a codebase / Model real domain objects with class hierarchies

What you'll learn

  • 1Install TypeScript and write a minimal tsconfig.json
  • 2Use the primitive types and literal types
  • 3Rely on type inference, annotate when needed
  • 4Run TS with tsx or compile with tsc
  • 5Define type aliases for object and union types
  • 6Distinguish any from unknown
  • 7Use never for exhaustive switch checks
  • 8Narrow with typeof, in, and discriminated unions
  • 9Define object shapes with interface
  • 10Extend interfaces and intersect types
  • 11Explain structural ("duck") typing
  • 12Pick interface for libraries, type for everything else
  • 13Use access modifiers (public, private, protected)
  • 14Take advantage of parameter properties
  • 15Mark immutable fields with readonly
  • 16Define abstract base classes

TypeScript Basics

Add static types to JavaScript with TypeScript. Set up tsc, learn the primitive types, type inference, and the most useful tsconfig flags.

1. Why TypeScript?

  • Catch bugs at compile time, not at 3 AM
  • Editors show real autocomplete and refactors
  • Easier to navigate large codebases
  • Industry standard for any non-trivial JS project

2. Setup

bash
npm install --save-dev typescript tsx
npx tsc --init   # creates tsconfig.json
json
// tsconfig.json (key fields)
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "noEmit": true
  }
}

3. Primitive Types

typescript
let count: number = 0;
let name: string = "Alice";
let active: boolean = true;
let nothing: null = null;
let missing: undefined;
let ids: number[] = [1, 2, 3];
let pair: [string, number] = ["a", 1];   // tuple

// Type inference — let TS figure it out
const score = 100;          // inferred as number
const greeting = "hello";   // inferred as string

4. Literal Types & Unions

typescript
type Status = "pending" | "done" | "failed";
function setStatus(s: Status) { /* ... */ }
setStatus("done");
// setStatus("complete");  // error: not assignable

type ID = string | number;   // union

Type Aliases & any/unknown/never

Name complex types with type aliases, understand any (escape hatch), unknown (safe any), and never (impossible). Learn type narrowing.

1. Type Aliases

typescript
type User = {
  id: number;
  name: string;
  email?: string;       // optional
  readonly createdAt: Date;
};

const u: User = { id: 1, name: "Alice", createdAt: new Date() };

2. any vs unknown

typescript
// any: turn off type checking (use sparingly)
let a: any = JSON.parse(text);
a.whatever.does.not.error;

// unknown: safe — you must narrow before using
let u: unknown = JSON.parse(text);
if (typeof u === "object" && u !== null && "name" in u) {
  console.log((u as { name: string }).name);
}
💡

Reach for unknown when you must, any almost never. unknown forces you to validate before use.

3. never & Exhaustive Checks

typescript
type Shape = { kind: "circle"; r: number } | { kind: "square"; side: number };

function area(s: Shape): number {
  switch (s.kind) {
    case "circle": return Math.PI * s.r ** 2;
    case "square": return s.side ** 2;
    default: {
      const _exhaustive: never = s;   // compile error if a case is missed
      return _exhaustive;
    }
  }
}

4. Narrowing

typescript
function describe(value: string | number) {
  if (typeof value === "string") {
    return value.toUpperCase();
  }
  return value.toFixed(2);
}

function take(item: { kind: "a"; x: number } | { kind: "b"; y: string }) {
  if (item.kind === "a") item.x;   // narrowed to first variant
  else                   item.y;   // narrowed to second
}

Interface vs Type Alias

When to use interface and when to use type. Learn extends, declaration merging, and how structural typing decides assignability.

1. interface

typescript
interface User {
  id: number;
  name: string;
  email?: string;
  greet(): string;
}

const alice: User = {
  id: 1,
  name: "Alice",
  greet() { return `Hi, ${this.name}`; },
};

2. Extending

typescript
interface Animal { name: string }
interface Dog extends Animal { bark(): void }

// Type alias intersection — equivalent
type DogT = Animal & { bark(): void };

3. interface vs type — When

NeedPick
Object shape, especially for public APIinterface
Union, tuple, primitive aliastype
Need declaration merginginterface
Computed / mapped typestype
💡

Many teams pick one consistently and stick with it. Either works for most cases.

4. Structural Typing

typescript
interface Point { x: number; y: number }

function print(p: Point) { console.log(p.x, p.y); }
print({ x: 1, y: 2, color: "red" });   // OK — extra props allowed at call site

// TS asks "does it have the right shape?" — not "is it nominally a Point?"

Classes in TypeScript

Use TypeScript's class features: access modifiers, parameter properties, readonly, and abstract classes for shared base behavior.

1. Basic Class

typescript
class BankAccount {
  private balance: number = 0;

  constructor(public readonly owner: string) {}

  deposit(amount: number): void {
    if (amount <= 0) throw new Error("amount must be positive");
    this.balance += amount;
  }

  getBalance(): number {
    return this.balance;
  }
}

const acct = new BankAccount("Alice");
acct.deposit(100);
// acct.balance = 0;   // error: private

public readonly owner: string is a parameter property — it both accepts the arg and assigns this.owner in one place.

2. Inheritance & abstract

typescript
abstract class Shape {
  abstract area(): number;
  describe(): string { return `area=${this.area()}`; }
}

class Circle extends Shape {
  constructor(private r: number) { super(); }
  area() { return Math.PI * this.r ** 2; }
}

class Rect extends Shape {
  constructor(private w: number, private h: number) { super(); }
  area() { return this.w * this.h; }
}

const shapes: Shape[] = [new Circle(5), new Rect(3, 4)];
shapes.forEach(s => console.log(s.describe()));

3. implements an Interface

typescript
interface Serializable { toJSON(): string }

class Note implements Serializable {
  constructor(public title: string, public body: string) {}
  toJSON() { return JSON.stringify(this); }
}
Example code / lecture materials

All lecture materials and example code are openly available on GitHub.

View on GitHub ↗

Comments 0

No comments yet. Be the first.

Only members can comment.

Comments with ads, abuse, personal information or illegal content are hidden or removed. Comments are shown with your nickname. Privacy Policy