TypeScript Fundamentals

Types, interfaces, generics, enums, and utility types

Core Type System

ts
// Type Basics
// Primitive types
let name: string = "Alice";
let age: number = 28;
let active: boolean = true;

// Arrays & Tuples
let ids: number[] = [1, 2, 3];
let pair: [string, number] = ["age", 28];

// Union & Intersection
type Status = "active" | "inactive" | "banned";
type AdminUser = User & { permissions: string[] };

// Literal types
type Direction = "up" | "down" | "left" | "right";

// Interface — extendable, for objects
interface User {
  id: number;
  name: string;
  email: string;
  role?: string; // optional
  readonly createdAt: Date;
}

// Type alias — for unions, primitives, tuples
type Result<T> = { success: true; data: T } | { success: false; error: string };

// Extending interfaces
interface Admin extends User {
  permissions: string[];
}

Generics & Utility Types

ts
// Advanced TypeScript
// Generics — reusable type-safe functions
function identity<T>(value: T): T {
  return value;
}
identity<string>("hello"); // type-safe

// Generic constraints
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

// Utility types
type PartialUser = Partial<User>;        // all optional
type RequiredUser = Required<User>;       // all required
type ReadonlyUser = Readonly<User>;       // all readonly
type UserPreview = Pick<User, "id" | "name">;
type UserUpdate = Omit<User, "id" | "createdAt">;
type UserRecord = Record<string, User>;   // { [key: string]: User }

// Enums
enum HttpStatus {
  OK = 200,
  NotFound = 404,
  ServerError = 500,
}

// Type narrowing
function processValue(value: string | number) {
  if (typeof value === "string") {
    return value.toUpperCase(); // TS knows it's string
  }
  return value.toFixed(2);     // TS knows it's number
}

// Discriminated unions
type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "rect"; width: number; height: number };

function area(shape: Shape): number {
  switch (shape.kind) {
    case "circle": return Math.PI * shape.radius ** 2;
    case "rect": return shape.width * shape.height;
  }
}

Interview Q&A

💬 Interface vs Type — when to use which?

Interfaces are best for object shapes and can be extended/merged. Types are more flexible — unions, intersections, primitives, tuples. Use interfaces for public APIs (extendable), types for everything else.

💬 What is type narrowing?

Type narrowing is when TypeScript reduces a union type to a more specific type based on control flow checks (typeof, instanceof, in operator, discriminated unions). It lets TS infer the correct type in each branch.