TSTypeScript · Lesson 3 of 10

Interfaces & Type Aliases

Interfaces and type aliases both let you name a shape. The difference is subtle — interfaces are open (extendable), type aliases are closed. In practice, use whichever your team prefers. The important thing is using them.

TypeScript
// Interface
interface User {
  id: number
  name: string
  email?: string        // optional property
  readonly createdAt: Date  // can't be reassigned after creation
}

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

// user.createdAt = new Date()   // Error: readonly

// Extending interfaces
interface AdminUser extends User {
  role: "admin" | "superadmin"
  permissions: string[]
}

// Type alias — can do everything interfaces can, plus more
type Point = {
  x: number
  y: number
}

// Type aliases can represent primitives, unions, intersections
type ID      = string | number
type Status  = "active" | "inactive" | "pending"  // literal union type

// Intersection types — combine multiple types
type TimestampedUser = User & {
  updatedAt: Date
  version: number
}

const admin: AdminUser = {
  id: 2,
  name: "Bob",
  createdAt: new Date(),
  role: "admin",
  permissions: ["read", "write", "delete"],
}
TypeScript
// Index signatures — object with dynamic keys
interface StringMap {
  [key: string]: string
}

const config: StringMap = {
  host: "localhost",
  port: "3000",
  env: "development",
}

// Function types in interfaces
interface Transformer<T, U> {
  (input: T): U
}

const double: Transformer<number, number> = (n) => n * 2
const stringify: Transformer<number, string> = (n) => String(n)

// Discriminated unions — tagged union types
type Shape =
  | { kind: "circle";    radius: number }
  | { kind: "rectangle"; width: number; height: number }
  | { kind: "triangle";  base: number;  height: number }

function area(shape: Shape): number {
  switch (shape.kind) {
    case "circle":
      return Math.PI * shape.radius ** 2
    case "rectangle":
      return shape.width * shape.height
    case "triangle":
      return 0.5 * shape.base * shape.height
  }
  // TypeScript knows all cases are handled — no default needed
}

console.log(area({ kind: "circle", radius: 5 }))     // 78.54...
console.log(area({ kind: "rectangle", width: 4, height: 6 }))  // 24
✦ Tip
Use literal union types like `"active" | "inactive"` instead of plain strings wherever you have a fixed set of values. TypeScript will then catch typos at compile time, and your editor will autocomplete the valid values.