100 TypeScript Concepts

A comprehensive guide to TypeScript concepts with practical examples.

1. Basic Types

Understanding TypeScript's basic type system.

// String
let name: string = "John";

// Number
let age: number = 30;
let price: number = 19.99;

// Boolean
let isActive: boolean = true;

// Array
let numbers: number[] = [1, 2, 3];
let names: Array<string> = ["Alice", "Bob"];

// Tuple
let person: [string, number] = ["John", 30];

// Enum
enum Color {
  Red,
  Green,
  Blue
}
let favoriteColor: Color = Color.Blue;

// Any
let dynamicValue: any = "Hello";
dynamicValue = 42;

// Unknown
let userInput: unknown = "Hello";
if (typeof userInput === "string") {
  console.log(userInput.toUpperCase());
}

// Void
function logMessage(message: string): void {
  console.log(message);
}

// Never
function throwError(message: string): never {
  throw new Error(message);
}

2. Control Flow

Understanding TypeScript's control flow analysis.

// Type narrowing with if statements
function processValue(value: string | number) {
  if (typeof value === "string") {
    // TypeScript knows value is string here
    console.log(value.toUpperCase());
  } else {
    // TypeScript knows value is number here
    console.log(value.toFixed(2));
  }
}

// Type guards
function isString(value: unknown): value is string {
  return typeof value === "string";
}

// Type narrowing with type guards
function processValueWithGuard(value: unknown) {
  if (isString(value)) {
    // TypeScript knows value is string here
    console.log(value.toUpperCase());
  }
}

// Type narrowing with instanceof
class Animal {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
}

class Dog extends Animal {
  bark() {
    return "Woof!";
  }
}

function processAnimal(animal: Animal) {
  if (animal instanceof Dog) {
    // TypeScript knows animal is Dog here
    console.log(animal.bark());
  }
}

3. Loops and Iteration

Understanding TypeScript's loop and iteration features.

// For...of loop with type inference
const numbers: number[] = [1, 2, 3, 4, 5];
for (const num of numbers) {
  // TypeScript knows num is number
  console.log(num.toFixed(2));
}

// For...in loop with type safety
interface Person {
  name: string;
  age: number;
}

const person: Person = { name: "John", age: 30 };
for (const key in person) {
  // TypeScript knows key is keyof Person
  console.log(person[key as keyof Person]);
}

// Array methods with type inference
const doubled = numbers.map(num => num * 2);
const evenNumbers = numbers.filter(num => num % 2 === 0);
const sum = numbers.reduce((acc, curr) => acc + curr, 0);

// Iterating over objects
const entries = Object.entries(person);
for (const [key, value] of entries) {
  console.log(key, value);
}

4. Functions

Understanding TypeScript's function features.

// Function type declarations
type MathOperation = (x: number, y: number) => number;

const add: MathOperation = (x, y) => x + y;
const subtract: MathOperation = (x, y) => x - y;

// Optional and default parameters
function greet(name: string, greeting: string = "Hello"): string {
  return `${greeting}, ${name}!`;
}

// Rest parameters
function sum(...numbers: number[]): number {
  return numbers.reduce((acc, curr) => acc + curr, 0);
}

// Function overloads
function process(x: number): number;
function process(x: string): string;
function process(x: number | string): number | string {
  return typeof x === "number" ? x * 2 : x.toUpperCase();
}

// Generic functions
function identity<T>(arg: T): T {
  return arg;
}

// Async functions
async function fetchData<T>(url: string): Promise<T> {
  const response = await fetch(url);
  return response.json();
}

5. Objects and Interfaces

Understanding TypeScript's object and interface features.

// Interface definition
interface User {
  id: number;
  name: string;
  email: string;
  age?: number; // Optional property
  readonly createdAt: Date; // Read-only property
}

// Implementing an interface
const user: User = {
  id: 1,
  name: "John Doe",
  email: "john@example.com",
  createdAt: new Date()
};

// Extending interfaces
interface Employee extends User {
  department: string;
  salary: number;
}

// Type aliases
type Point = {
  x: number;
  y: number;
};

// Intersection types
type EmployeeWithContact = Employee & {
  phone: string;
  address: string;
};

// Index signatures
interface StringMap {
  [key: string]: string;
}

// Mapped types
type ReadonlyUser = {
  readonly [K in keyof User]: User[K];
};

6. Classes and Inheritance

Understanding TypeScript's class and inheritance features.

// Class definition
class Animal {
  protected name: string;
  
  constructor(name: string) {
    this.name = name;
  }
  
  move(distance: number = 0) {
    console.log(`${this.name} moved ${distance}m.`);
  }
}

// Inheritance
class Dog extends Animal {
  bark() {
    console.log("Woof! Woof!");
  }
}

// Abstract classes
abstract class Vehicle {
  abstract start(): void;
  abstract stop(): void;
}

class Car extends Vehicle {
  start() {
    console.log("Starting car...");
  }
  
  stop() {
    console.log("Stopping car...");
  }
}

// Access modifiers
class BankAccount {
  private balance: number;
  public readonly accountNumber: string;
  
  constructor(accountNumber: string, initialBalance: number) {
    this.accountNumber = accountNumber;
    this.balance = initialBalance;
  }
  
  public deposit(amount: number): void {
    this.balance += amount;
  }
  
  public getBalance(): number {
    return this.balance;
  }
}

7. Generics

Understanding TypeScript's generic features.

// Generic function
function identity<T>(arg: T): T {
  return arg;
}

// Generic interface
interface Container<T> {
  value: T;
  getValue(): T;
}

// Generic class
class Box<T> {
  private content: T;
  
  constructor(value: T) {
    this.content = value;
  }
  
  getValue(): T {
    return this.content;
  }
}

// Generic constraints
interface Lengthwise {
  length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
  console.log(arg.length);
  return arg;
}

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

// Generic utility types
type Partial<T> = {
  [P in keyof T]?: T[P];
};

type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};

8. Error Handling

Understanding TypeScript's error handling features.

// Custom error class
class ValidationError extends Error {
  constructor(message: string) {
    super(message);
    this.name = "ValidationError";
  }
}

// Try-catch with type narrowing
function parseJSON(json: string): unknown {
  try {
    return JSON.parse(json);
  } catch (error) {
    if (error instanceof Error) {
      throw new ValidationError(`Invalid JSON: ${error.message}`);
    }
    throw error;
  }
}

// Error handling with async/await
async function fetchData(url: string): Promise<unknown> {
  try {
    const response = await fetch(url);
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return await response.json();
  } catch (error) {
    if (error instanceof Error) {
      console.error("Error fetching data:", error.message);
    }
    throw error;
  }
}

// Type guards for error handling
function isError(error: unknown): error is Error {
  return error instanceof Error;
}

// Error handling with Result type
type Result<T, E = Error> = {
  success: true;
  data: T;
} | {
  success: false;
  error: E;
};

function safeOperation<T>(operation: () => T): Result<T> {
  try {
    const data = operation();
    return { success: true, data };
  } catch (error) {
    return {
      success: false,
      error: error instanceof Error ? error : new Error(String(error))
    };
  }
}

9. Async/Await

Understanding TypeScript's async/await features.

// Async function with type annotations
async function fetchUser(id: number): Promise<User> {
  const response = await fetch(`/api/users/${id}`);
  if (!response.ok) {
    throw new Error(`Failed to fetch user: ${response.statusText}`);
  }
  return response.json();
}

// Promise.all with type inference
async function fetchMultipleUsers(ids: number[]): Promise<User[]> {
  const promises = ids.map(id => fetchUser(id));
  return Promise.all(promises);
}

// Async error handling
async function safeFetch<T>(url: string): Promise<T> {
  try {
    const response = await fetch(url);
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return response.json();
  } catch (error) {
    console.error("Fetch error:", error);
    throw error;
  }
}

// Async function with timeout
async function fetchWithTimeout<T>(
  url: string,
  timeout: number
): Promise<T> {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), timeout);

  try {
    const response = await fetch(url, { signal: controller.signal });
    clearTimeout(timeoutId);
    return response.json();
  } catch (error) {
    clearTimeout(timeoutId);
    if (error instanceof Error) {
      throw new Error(`Request failed: ${error.message}`);
    }
    throw error;
  }
}

// Async function with retry logic
async function fetchWithRetry<T>(
  url: string,
  retries: number = 3
): Promise<T> {
  for (let i = 0; i < retries; i++) {
    try {
      return await fetchWithTimeout<T>(url, 5000);
    } catch (error) {
      if (i === retries - 1) throw error;
      await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
    }
  }
  throw new Error("All retries failed");
}

10. Type Guards and Type Assertions

Understanding TypeScript's type guards and assertions.

// Type guards
function isString(value: unknown): value is string {
  return typeof value === "string";
}

function isNumber(value: unknown): value is number {
  return typeof value === "number";
}

// Type assertions
let value: unknown = "Hello";
let length: number = (value as string).length;

// Type predicates
interface Bird {
  type: "bird";
  flyingSpeed: number;
}

interface Horse {
  type: "horse";
  runningSpeed: number;
}

type Animal = Bird | Horse;

function isBird(animal: Animal): animal is Bird {
  return animal.type === "bird";
}

// Type narrowing with instanceof
class Car {
  drive() {
    console.log("Driving...");
  }
}

class Truck {
  load() {
    console.log("Loading...");
  }
}

type Vehicle = Car | Truck;

function useVehicle(vehicle: Vehicle) {
  if (vehicle instanceof Car) {
    vehicle.drive();
  } else {
    vehicle.load();
  }
}

// Type narrowing with in operator
interface Circle {
  kind: "circle";
  radius: number;
}

interface Square {
  kind: "square";
  sideLength: number;
}

type Shape = Circle | Square;

function getArea(shape: Shape): number {
  if ("radius" in shape) {
    return Math.PI * shape.radius ** 2;
  } else {
    return shape.sideLength ** 2;
  }
}

11. Array Methods

Understanding TypeScript's array manipulation methods.

// Array methods with type safety
const numbers: number[] = [1, 2, 3, 4, 5];

// map with type inference
const doubled = numbers.map(num => num * 2);

// filter with type guards
const evenNumbers = numbers.filter((num): num is number => num % 2 === 0);

// reduce with accumulator type
const sum = numbers.reduce((acc: number, curr) => acc + curr, 0);

// find with type narrowing
const firstEven = numbers.find((num): num is number => num % 2 === 0);

// some and every with type predicates
const hasEven = numbers.some((num): num is number => num % 2 === 0);
const allPositive = numbers.every((num): num is number => num > 0);

// flatMap with type inference
const matrix: number[][] = [[1, 2], [3, 4], [5, 6]];
const flattened = matrix.flatMap(row => row);

// sort with type-safe comparison
const sorted = [...numbers].sort((a, b) => a - b);

// slice with type preservation
const middle = numbers.slice(1, 4);

// splice with type safety
const removed = [...numbers].splice(1, 2);

12. String Manipulation

Understanding TypeScript's string handling features.

// String type safety
const str: string = "Hello, TypeScript!";

// Template literals with type inference
const name: string = "John";
const greeting = `Hello, ${name}!`;

// String methods with type safety
const upper = str.toUpperCase();
const lower = str.toLowerCase();
const trimmed = str.trim();
const replaced = str.replace("TypeScript", "JavaScript");

// String splitting with type inference
const words: string[] = str.split(" ");

// String joining with type safety
const joined = words.join("-");

// String searching with type guards
const hasTypeScript = str.includes("TypeScript");
const startsWithHello = str.startsWith("Hello");
const endsWithScript = str.endsWith("Script");

// String slicing with type preservation
const substring = str.slice(0, 5);

// String padding with type safety
const padded = str.padStart(20, "*");

// String repeating with type checking
const repeated = "*".repeat(5);

13. Date and Time

Understanding TypeScript's date and time handling.

// Date type safety
const now: Date = new Date();

// Date creation with type inference
const specificDate = new Date(2024, 2, 15); // March 15, 2024
const fromString = new Date("2024-03-15");
const fromTimestamp = new Date(1710432000000);

// Date methods with type safety
const year = now.getFullYear();
const month = now.getMonth();
const day = now.getDate();
const hours = now.getHours();
const minutes = now.getMinutes();
const seconds = now.getSeconds();

// Date formatting with type preservation
const formatted = now.toLocaleDateString("en-US", {
  year: "numeric",
  month: "long",
  day: "numeric"
});

// Date arithmetic with type safety
const tomorrow = new Date(now.getTime() + 24 * 60 * 60 * 1000);
const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000);

// Date comparison with type guards
const isFuture = (date: Date): boolean => date > now;
const isPast = (date: Date): boolean => date < now;

// Date difference calculation
function getDaysBetween(date1: Date, date2: Date): number {
  const diffTime = Math.abs(date2.getTime() - date1.getTime());
  return Math.ceil(diffTime / (1000 * 60 * 60 * 24));
}

14. Regular Expressions

Understanding TypeScript's regex features.

// Regex type safety
const emailRegex: RegExp = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i;

// Regex creation with type inference
const phoneRegex = new RegExp("^\+?[1-9]\d{1,14}$");
const urlRegex = /^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .-]*)*\/?$/;

// Regex testing with type guards
function isValidEmail(email: string): boolean {
  return emailRegex.test(email);
}

// Regex matching with type inference
function extractPhoneNumbers(text: string): string[] {
  const matches = text.match(/\+?[1-9]\d{1,14}/g) || [];
  return matches;
}

// Regex replacement with type safety
function maskEmail(email: string): string {
  return email.replace(/(?<=.{3}).(?=.*@)/g, "*");
}

// Regex groups with type preservation
function parseDate(dateStr: string): { year: number; month: number; day: number } | null {
  const match = dateStr.match(/(\d{4})-(\d{2})-(\d{2})/);
  if (!match) return null;
  
  return {
    year: parseInt(match[1]),
    month: parseInt(match[2]),
    day: parseInt(match[3])
  };
}

// Regex flags with type safety
const globalRegex = /pattern/g;
const caseInsensitiveRegex = /pattern/i;
const multilineRegex = /pattern/m;

// Regex with Unicode support
const unicodeRegex = /\p{Emoji}/u;

15. Working with APIs

Understanding TypeScript's API integration features.

// API response types
interface User {
  id: number;
  name: string;
  email: string;
}

interface Post {
  id: number;
  title: string;
  body: string;
  userId: number;
}

// API client with type safety
class ApiClient {
  private baseUrl: string;

  constructor(baseUrl: string) {
    this.baseUrl = baseUrl;
  }

  async get<T>(endpoint: string): Promise<T> {
    const response = await fetch(`${this.baseUrl}${endpoint}`);
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return response.json();
  }

  async post<T>(endpoint: string, data: unknown): Promise<T> {
    const response = await fetch(`${this.baseUrl}${endpoint}`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify(data)
    });
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return response.json();
  }
}

// API usage with type inference
const api = new ApiClient("https://api.example.com");

async function fetchUser(id: number): Promise<User> {
  return api.get<User>(`/users/${id}`);
}

async function createPost(post: Omit<Post, "id">): Promise<Post> {
  return api.post<Post>("/posts", post);
}

// API error handling with type guards
interface ApiError {
  code: string;
  message: string;
}

function isApiError(error: unknown): error is ApiError {
  return (
    typeof error === "object" &&
    error !== null &&
    "code" in error &&
    "message" in error
  );
}

// API response caching with type safety
class Cache<T> {
  private cache: Map<string, { data: T; timestamp: number }>;
  private ttl: number;

  constructor(ttl: number) {
    this.cache = new Map();
    this.ttl = ttl;
  }

  set(key: string, data: T): void {
    this.cache.set(key, { data, timestamp: Date.now() });
  }

  get(key: string): T | null {
    const item = this.cache.get(key);
    if (!item) return null;
    if (Date.now() - item.timestamp > this.ttl) {
      this.cache.delete(key);
      return null;
    }
    return item.data;
  }
}

// Type-safe API response
interface ApiResponse<T> {
  data: T;
  status: number;
  message: string;
}

async function fetchJson<T>(url: string): Promise<ApiResponse<T>> {
  const response = await fetch(url);
  const data = await response.json();
  return {
    data,
    status: response.status,
    message: response.statusText
  };
}

16. State Management

Understanding TypeScript's state management patterns.

// State management with type safety
interface State {
  count: number;
  todos: Todo[];
  filter: "all" | "active" | "completed";
}

interface Todo {
  id: number;
  text: string;
  completed: boolean;
}

// Action types with discriminated unions
type Action =
  | { type: "INCREMENT" }
  | { type: "DECREMENT" }
  | { type: "ADD_TODO"; payload: string }
  | { type: "TOGGLE_TODO"; payload: number }
  | { type: "SET_FILTER"; payload: State["filter"] };

// Reducer with type safety
function reducer(state: State, action: Action): State {
  switch (action.type) {
    case "INCREMENT":
      return { ...state, count: state.count + 1 };
    case "DECREMENT":
      return { ...state, count: state.count - 1 };
    case "ADD_TODO":
      return {
        ...state,
        todos: [
          ...state.todos,
          {
            id: Date.now(),
            text: action.payload,
            completed: false
          }
        ]
      };
    case "TOGGLE_TODO":
      return {
        ...state,
        todos: state.todos.map(todo =>
          todo.id === action.payload
            ? { ...todo, completed: !todo.completed }
            : todo
        )
      };
    case "SET_FILTER":
      return { ...state, filter: action.payload };
    default:
      return state;
  }
}

// Store with type safety
class Store<T> {
  private state: T;
  private listeners: Set<(state: T) => void>;

  constructor(initialState: T) {
    this.state = initialState;
    this.listeners = new Set();
  }

  getState(): T {
    return this.state;
  }

  setState(newState: T): void {
    this.state = newState;
    this.notify();
  }

  subscribe(listener: (state: T) => void): () => void {
    this.listeners.add(listener);
    return () => this.listeners.delete(listener);
  }

  private notify(): void {
    this.listeners.forEach(listener => listener(this.state));
  }
}

// Usage with type inference
const initialState: State = {
  count: 0,
  todos: [],
  filter: "all"
};

const store = new Store<State>(initialState);

// Action creators with type safety
const increment = (): Action => ({ type: "INCREMENT" });
const decrement = (): Action => ({ type: "DECREMENT" });
const addTodo = (text: string): Action => ({ type: "ADD_TODO", payload: text });
const toggleTodo = (id: number): Action => ({ type: "TOGGLE_TODO", payload: id });
const setFilter = (filter: State["filter"]): Action => ({ type: "SET_FILTER", payload: filter });

17. Testing

Understanding TypeScript's testing features.

// Test types with Jest
import { describe, it, expect, beforeEach } from "@jest/globals";

// Type-safe test suite
describe("Calculator", () => {
  let calculator: Calculator;

  beforeEach(() => {
    calculator = new Calculator();
  });

  it("should add two numbers", () => {
    const result = calculator.add(2, 3);
    expect(result).toBe(5);
  });

  it("should subtract two numbers", () => {
    const result = calculator.subtract(5, 3);
    expect(result).toBe(2);
  });
});

// Type-safe test utilities
function createTestUser(overrides?: Partial<User>): User {
  return {
    id: 1,
    name: "Test User",
    email: "test@example.com",
    ...overrides
  };
}

// Type-safe mock functions
type MockFunction<T extends (...args: any[]) => any> = jest.Mock<ReturnType<T>, Parameters<T>>;

function createMockApi<T>(): MockFunction<() => Promise<T>> {
  return jest.fn();
}

// Type-safe test data
interface TestData {
  input: number;
  expected: number;
}

const testCases: TestData[] = [
  { input: 2, expected: 4 },
  { input: 3, expected: 6 },
  { input: 4, expected: 8 }
];

// Type-safe test helpers
function assertType<T>(value: T): void {
  // This function helps TypeScript infer types in tests
  expect(value).toBeDefined();
}

// Type-safe async tests
async function testAsyncOperation<T>(
  operation: () => Promise<T>,
  expected: T
): Promise<void> {
  const result = await operation();
  expect(result).toEqual(expected);
}

// Type-safe test matchers
expect.extend({
  toBeWithinRange(received: number, floor: number, ceiling: number) {
    const pass = received >= floor && received <= ceiling;
    if (pass) {
      return {
        message: () =>
          `expected ${received} not to be within range ${floor} - ${ceiling}`,
        pass: true
      };
    } else {
      return {
        message: () =>
          `expected ${received} to be within range ${floor} - ${ceiling}`,
        pass: false
      };
    }
  }
});

18. Debugging

Understanding TypeScript's debugging features.

// Debug types with type safety
interface DebugConfig {
  enabled: boolean;
  level: "info" | "warn" | "error";
  prefix?: string;
}

// Type-safe debug logger
class DebugLogger {
  private config: DebugConfig;

  constructor(config: DebugConfig) {
    this.config = config;
  }

  log(message: string, data?: unknown): void {
    if (!this.config.enabled) return;
    console.log(`${this.config.prefix || ""} ${message}`, data);
  }

  warn(message: string, data?: unknown): void {
    if (!this.config.enabled || this.config.level === "info") return;
    console.warn(`${this.config.prefix || ""} ${message}`, data);
  }

  error(message: string, data?: unknown): void {
    if (!this.config.enabled || this.config.level === "info" || this.config.level === "warn") return;
    console.error(`${this.config.prefix || ""} ${message}`, data);
  }
}

// Type-safe debug utilities
function debugValue<T>(value: T, label?: string): T {
  console.log(label ? `${label}:` : "Debug:", value);
  return value;
}

// Type-safe debug assertions
function assertType<T>(value: unknown, type: string): asserts value is T {
  if (typeof value !== type) {
    throw new Error(`Expected ${type}, got ${typeof value}`);
  }
}

// Type-safe debug timing
function measureTime<T>(fn: () => T): T {
  const start = performance.now();
  const result = fn();
  const end = performance.now();
  console.log(`Execution time: ${end - start}ms`);
  return result;
}

// Type-safe debug memory
function logMemoryUsage(): void {
  if (typeof process !== "undefined") {
    const used = process.memoryUsage();
    console.log("Memory usage:", {
      heapTotal: `${Math.round(used.heapTotal / 1024 / 1024)}MB`,
      heapUsed: `${Math.round(used.heapUsed / 1024 / 1024)}MB`,
      external: `${Math.round(used.external / 1024 / 1024)}MB`
    });
  }
}

// Type-safe debug stack traces
function getStackTrace(): string {
  const stack = new Error().stack;
  return stack ? stack.split("\n").slice(2).join("\n") : "";
}

19. Performance Optimization

Understanding TypeScript's performance optimization features.

// Performance types with type safety
interface PerformanceMetrics {
  startTime: number;
  endTime: number;
  duration: number;
  memory?: {
    heapUsed: number;
    heapTotal: number;
  };
}

// Type-safe performance measurement
class PerformanceMonitor {
  private metrics: Map<string, PerformanceMetrics>;

  constructor() {
    this.metrics = new Map();
  }

  start(label: string): void {
    this.metrics.set(label, {
      startTime: performance.now(),
      endTime: 0,
      duration: 0
    });
  }

  end(label: string): PerformanceMetrics {
    const metric = this.metrics.get(label);
    if (!metric) {
      throw new Error(`No metric found for label: ${label}`);
    }

    metric.endTime = performance.now();
    metric.duration = metric.endTime - metric.startTime;

    if (typeof process !== "undefined") {
      const memory = process.memoryUsage();
      metric.memory = {
        heapUsed: memory.heapUsed,
        heapTotal: memory.heapTotal
      };
    }

    return metric;
  }
}

// Type-safe memoization
function memoize<T extends (...args: any[]) => any>(
  fn: T,
  keyFn: (...args: Parameters<T>) => string = (...args) => JSON.stringify(args)
): T {
  const cache = new Map<string, ReturnType<T>>();

  return ((...args: Parameters<T>): ReturnType<T> => {
    const key = keyFn(...args);
    if (cache.has(key)) {
      return cache.get(key)!;
    }

    const result = fn(...args);
    cache.set(key, result);
    return result;
  }) as T;
}

// Type-safe debouncing
function debounce<T extends (...args: any[]) => any>(
  fn: T,
  delay: number
): (...args: Parameters<T>) => void {
  let timeoutId: NodeJS.Timeout;

  return (...args: Parameters<T>) => {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => fn(...args), delay);
  };
}

// Type-safe throttling
function throttle<T extends (...args: any[]) => any>(
  fn: T,
  limit: number
): (...args: Parameters<T>) => void {
  let inThrottle: boolean;
  let lastResult: ReturnType<T>;

  return (...args: Parameters<T>) => {
    if (!inThrottle) {
      fn(...args);
      inThrottle = true;
      setTimeout(() => (inThrottle = false), limit);
    }
  };
}

// Type-safe lazy loading
class LazyLoader<T> {
  private value: T | null = null;
  private loader: () => Promise<T>;

  constructor(loader: () => Promise<T>) {
    this.loader = loader;
  }

  async getValue(): Promise<T> {
    if (!this.value) {
      this.value = await this.loader();
    }
    return this.value;
  }
}

20. Best Practices

Understanding TypeScript's best practices.

// Type-safe configuration
interface Config {
  apiUrl: string;
  timeout: number;
  retries: number;
  features: {
    darkMode: boolean;
    notifications: boolean;
  };
}

// Type-safe environment variables
const config: Config = {
  apiUrl: process.env.API_URL || "https://api.example.com",
  timeout: parseInt(process.env.TIMEOUT || "5000", 10),
  retries: parseInt(process.env.RETRIES || "3", 10),
  features: {
    darkMode: process.env.DARK_MODE === "true",
    notifications: process.env.NOTIFICATIONS === "true"
  }
};

// Type-safe error handling
class AppError extends Error {
  constructor(
    message: string,
    public code: string,
    public status: number
  ) {
    super(message);
    this.name = "AppError";
  }
}

// Type-safe validation
function validateConfig(config: unknown): asserts config is Config {
  if (
    typeof config !== "object" ||
    config === null ||
    !("apiUrl" in config) ||
    !("timeout" in config) ||
    !("retries" in config) ||
    !("features" in config)
  ) {
    throw new AppError("Invalid configuration", "INVALID_CONFIG", 400);
  }
}

// Type-safe dependency injection
interface Service {
  getData(): Promise<unknown>;
}

class ServiceImpl implements Service {
  async getData(): Promise<unknown> {
    return { data: "example" };
  }
}

class Container {
  private services: Map<string, Service>;

  constructor() {
    this.services = new Map();
  }

  register(name: string, service: Service): void {
    this.services.set(name, service);
  }

  get(name: string): Service {
    const service = this.services.get(name);
    if (!service) {
      throw new AppError(`Service not found: ${name}`, "SERVICE_NOT_FOUND", 404);
    }
    return service;
  }
}

// Type-safe logging
interface Logger {
  info(message: string, ...args: unknown[]): void;
  warn(message: string, ...args: unknown[]): void;
  error(message: string, ...args: unknown[]): void;
}

class ConsoleLogger implements Logger {
  info(message: string, ...args: unknown[]): void {
    console.log(`[INFO] ${message}`, ...args);
  }

  warn(message: string, ...args: unknown[]): void {
    console.warn(`[WARN] ${message}`, ...args);
  }

  error(message: string, ...args: unknown[]): void {
    console.error(`[ERROR] ${message}`, ...args);
  }
}

21. Modules and Imports

Understanding TypeScript's module system.

// Module exports with type safety
export interface User {
  id: number;
  name: string;
}

export type UserRole = "admin" | "user" | "guest";

export class UserService {
  private users: User[] = [];

  addUser(user: User): void {
    this.users.push(user);
  }

  getUser(id: number): User | undefined {
    return this.users.find(user => user.id === id);
  }
}

// Default exports with type safety
export default class AuthService {
  private currentUser: User | null = null;

  login(user: User): void {
    this.currentUser = user;
  }

  logout(): void {
    this.currentUser = null;
  }

  getCurrentUser(): User | null {
    return this.currentUser;
  }
}

// Re-exports with type preservation
export { UserService as UserManager } from "./user-service";
export type { User as UserType } from "./user-service";

// Dynamic imports with type safety
async function loadModule<T>(path: string): Promise<T> {
  const module = await import(path);
  return module.default;
}

// Namespace exports with type safety
export namespace Utils {
  export function formatDate(date: Date): string {
    return date.toLocaleDateString();
  }

  export function formatCurrency(amount: number): string {
    return new Intl.NumberFormat("en-US", {
      style: "currency",
      currency: "USD"
    }).format(amount);
  }
}

22. Working with JSON

Understanding TypeScript's JSON handling features.

// JSON type safety
interface User {
  id: number;
  name: string;
  email: string;
}

// Type-safe JSON parsing
function parseUser(json: string): User {
  const parsed = JSON.parse(json);
  if (!isUser(parsed)) {
    throw new Error("Invalid user data");
  }
  return parsed;
}

// Type guard for JSON validation
function isUser(value: unknown): value is User {
  return (
    typeof value === "object" &&
    value !== null &&
    "id" in value &&
    typeof value.id === "number" &&
    "name" in value &&
    typeof value.name === "string" &&
    "email" in value &&
    typeof value.email === "string"
  );
}

// Type-safe JSON stringification
function stringifyUser(user: User): string {
  return JSON.stringify(user, null, 2);
}

// Type-safe JSON transformation
function transformUser(user: User): Omit<User, "email"> {
  const { email, ...rest } = user;
  return rest;
}

// Type-safe JSON schema validation
interface Schema {
  type: string;
  properties: Record<string, unknown>;
  required: string[];
}

function validateAgainstSchema<T>(data: unknown, schema: Schema): data is T {
  // Implementation of schema validation
  return true;
}

// Type-safe JSON API response
interface ApiResponse<T> {
  data: T;
  status: number;
  message: string;
}

async function fetchJson<T>(url: string): Promise<ApiResponse<T>> {
  const response = await fetch(url);
  const data = await response.json();
  return {
    data,
    status: response.status,
    message: response.statusText
  };
}

23. File Operations

Understanding TypeScript's file handling features.

// File types with type safety
interface FileMetadata {
  name: string;
  size: number;
  type: string;
  lastModified: Date;
}

// Type-safe file reading
async function readFile(path: string): Promise<string> {
  const response = await fetch(path);
  if (!response.ok) {
    throw new Error(`Failed to read file: ${response.statusText}`);
  }
  return response.text();
}

// Type-safe file writing
async function writeFile(path: string, content: string): Promise<void> {
  const blob = new Blob([content], { type: "text/plain" });
  const response = await fetch(path, {
    method: "PUT",
    body: blob
  });
  if (!response.ok) {
    throw new Error(`Failed to write file: ${response.statusText}`);
  }
}

// Type-safe file operations
class FileManager {
  private files: Map<string, FileMetadata>;

  constructor() {
    this.files = new Map();
  }

  async addFile(file: File): Promise<void> {
    this.files.set(file.name, {
      name: file.name,
      size: file.size,
      type: file.type,
      lastModified: new Date(file.lastModified)
    });
  }

  getFileMetadata(name: string): FileMetadata | undefined {
    return this.files.get(name);
  }

  async deleteFile(name: string): Promise<void> {
    this.files.delete(name);
  }
}

// Type-safe file upload
interface UploadProgress {
  loaded: number;
  total: number;
  percentage: number;
}

async function uploadFile(
  file: File,
  onProgress?: (progress: UploadProgress) => void
): Promise<void> {
  const formData = new FormData();
  formData.append("file", file);

  const xhr = new XMLHttpRequest();
  xhr.upload.addEventListener("progress", event => {
    if (event.lengthComputable && onProgress) {
      onProgress({
        loaded: event.loaded,
        total: event.total,
        percentage: (event.loaded / event.total) * 100
      });
    }
  });

  return new Promise((resolve, reject) => {
    xhr.onload = () => resolve();
    xhr.onerror = () => reject(new Error("Upload failed"));
    xhr.open("POST", "/upload");
    xhr.send(formData);
  });
}

24. Event Handling

Understanding TypeScript's event handling features.

// Event types with type safety
interface EventMap {
  click: MouseEvent;
  keydown: KeyboardEvent;
  submit: Event;
  custom: CustomEvent;
}

// Type-safe event emitter
class EventEmitter<T extends EventMap> {
  private listeners: Map<keyof T, Set<(event: T[keyof T]) => void>>;

  constructor() {
    this.listeners = new Map();
  }

  on<K extends keyof T>(event: K, listener: (event: T[K]) => void): void {
    if (!this.listeners.has(event)) {
      this.listeners.set(event, new Set());
    }
    this.listeners.get(event)!.add(listener as any);
  }

  off<K extends keyof T>(event: K, listener: (event: T[K]) => void): void {
    this.listeners.get(event)?.delete(listener as any);
  }

  emit<K extends keyof T>(event: K, data: T[K]): void {
    this.listeners.get(event)?.forEach(listener => listener(data));
  }
}

// Type-safe event handling
class Button {
  private emitter: EventEmitter<EventMap>;

  constructor() {
    this.emitter = new EventEmitter();
  }

  onClick(listener: (event: MouseEvent) => void): void {
    this.emitter.on("click", listener);
  }

  onKeyDown(listener: (event: KeyboardEvent) => void): void {
    this.emitter.on("keydown", listener);
  }

  triggerClick(event: MouseEvent): void {
    this.emitter.emit("click", event);
  }
}

// Type-safe custom events
interface CustomEventData {
  detail: unknown;
}

class CustomEventEmitter extends EventEmitter<EventMap> {
  emitCustom(data: CustomEventData): void {
    this.emit("custom", new CustomEvent("custom", { detail: data }));
  }
}

// Type-safe event delegation
function delegateEvent<T extends Event>(
  element: HTMLElement,
  selector: string,
  event: string,
  handler: (event: T, target: HTMLElement) => void
): void {
  element.addEventListener(event, (e: Event) => {
    const target = (e.target as HTMLElement).closest(selector);
    if (target) {
      handler(e as T, target);
    }
  });
}

25. DOM Manipulation

Understanding TypeScript's DOM manipulation features.

// DOM types with type safety
interface ElementAttributes {
  id?: string;
  class?: string;
  style?: Partial<CSSStyleDeclaration>;
  [key: string]: string | undefined;
}

// Type-safe element creation
function createElement<K extends keyof HTMLElementTagNameMap>(
  tag: K,
  attributes?: ElementAttributes,
  children?: (string | Node)[]
): HTMLElementTagNameMap[K] {
  const element = document.createElement(tag);
  
  if (attributes) {
    Object.entries(attributes).forEach(([key, value]) => {
      if (value !== undefined) {
        element.setAttribute(key, value);
      }
    });
  }

  if (children) {
    children.forEach(child => {
      if (typeof child === "string") {
        element.appendChild(document.createTextNode(child));
      } else {
        element.appendChild(child);
      }
    });
  }

  return element;
}

// Type-safe element selection
function selectElement<K extends keyof HTMLElementTagNameMap>(
  selector: K
): HTMLElementTagNameMap[K] | null {
  return document.querySelector(selector);
}

// Type-safe element manipulation
class ElementManager {
  private element: HTMLElement;

  constructor(element: HTMLElement) {
    this.element = element;
  }

  setText(text: string): void {
    this.element.textContent = text;
  }

  setHTML(html: string): void {
    this.element.innerHTML = html;
  }

  addClass(className: string): void {
    this.element.classList.add(className);
  }

  removeClass(className: string): void {
    this.element.classList.remove(className);
  }

  setStyle(style: Partial<CSSStyleDeclaration>): void {
    Object.assign(this.element.style, style);
  }
}

// Type-safe event binding
function bindEvent<K extends keyof HTMLElementEventMap>(
  element: HTMLElement,
  event: K,
  handler: (event: HTMLElementEventMap[K]) => void
): void {
  element.addEventListener(event, handler);
}

// Type-safe element animation
interface AnimationOptions {
  duration: number;
  easing: string;
  delay?: number;
}

function animateElement(
  element: HTMLElement,
  properties: Partial<CSSStyleDeclaration>,
  options: AnimationOptions
): Promise<void> {
  return new Promise(resolve => {
    const animation = element.animate(
      [element.style, properties],
      {
        duration: options.duration,
        easing: options.easing,
        delay: options.delay
      }
    );

    animation.onfinish = () => resolve();
  });
}

26. Form Handling

Understanding TypeScript's form handling features.

// Form types with type safety
interface FormData {
  [key: string]: string | number | boolean | File | null;
}

interface ValidationRule {
  required?: boolean;
  minLength?: number;
  maxLength?: number;
  pattern?: RegExp;
  custom?: (value: unknown) => boolean;
}

// Type-safe form validation
class FormValidator {
  private rules: Map<string, ValidationRule>;

  constructor() {
    this.rules = new Map();
  }

  addRule(field: string, rule: ValidationRule): void {
    this.rules.set(field, rule);
  }

  validate(data: FormData): Map<string, string[]> {
    const errors = new Map<string, string[]>();

    for (const [field, rule] of this.rules) {
      const value = data[field];
      const fieldErrors: string[] = [];

      if (rule.required && !value) {
        fieldErrors.push("This field is required");
      }

      if (typeof value === "string") {
        if (rule.minLength && value.length < rule.minLength) {
          fieldErrors.push(`Minimum length is ${rule.minLength}`);
        }

        if (rule.maxLength && value.length > rule.maxLength) {
          fieldErrors.push(`Maximum length is ${rule.maxLength}`);
        }

        if (rule.pattern && !rule.pattern.test(value)) {
          fieldErrors.push("Invalid format");
        }
      }

      if (rule.custom && !rule.custom(value)) {
        fieldErrors.push("Invalid value");
      }

      if (fieldErrors.length > 0) {
        errors.set(field, fieldErrors);
      }
    }

    return errors;
  }
}

// Type-safe form handling
class FormHandler {
  private form: HTMLFormElement;
  private validator: FormValidator;

  constructor(form: HTMLFormElement) {
    this.form = form;
    this.validator = new FormValidator();
  }

  addValidation(field: string, rule: ValidationRule): void {
    this.validator.addRule(field, rule);
  }

  async handleSubmit(
    onSubmit: (data: FormData) => Promise<void>
  ): Promise<void> {
    this.form.addEventListener("submit", async event => {
      event.preventDefault();

      const formData = new FormData(this.form);
      const data: FormData = {};

      for (const [key, value] of formData.entries()) {
        data[key] = value;
      }

      const errors = this.validator.validate(data);
      if (errors.size > 0) {
        this.displayErrors(errors);
        return;
      }

      try {
        await onSubmit(data);
        this.form.reset();
      } catch (error) {
        console.error("Form submission failed:", error);
      }
    });
  }

  private displayErrors(errors: Map<string, string[]>): void {
    for (const [field, fieldErrors] of errors) {
      const element = this.form.elements.namedItem(field) as HTMLElement;
      if (element) {
        const errorElement = document.createElement("div");
        errorElement.className = "error-message";
        errorElement.textContent = fieldErrors.join(", ");
        element.parentNode?.appendChild(errorElement);
      }
    }
  }
}

// Type-safe form field
class FormField<T> {
  private value: T;
  private onChange: (value: T) => void;

  constructor(initialValue: T, onChange: (value: T) => void) {
    this.value = initialValue;
    this.onChange = onChange;
  }

  setValue(value: T): void {
    this.value = value;
    this.onChange(value);
  }

  getValue(): T {
    return this.value;
  }
}

27. Local Storage

Understanding TypeScript's local storage features.

// Local storage types with type safety
interface StorageItem<T> {
  key: string;
  value: T;
  timestamp: number;
}

// Type-safe local storage manager
class LocalStorageManager {
  private prefix: string;

  constructor(prefix: string = "app_") {
    this.prefix = prefix;
  }

  private getKey(key: string): string {
    return `${this.prefix}${key}`;
  }

  set<T>(key: string, value: T): void {
    const item: StorageItem<T> = {
      key,
      value,
      timestamp: Date.now()
    };
    localStorage.setItem(this.getKey(key), JSON.stringify(item));
  }

  get<T>(key: string): T | null {
    const item = localStorage.getItem(this.getKey(key));
    if (!item) return null;

    try {
      const parsed = JSON.parse(item) as StorageItem<T>;
      return parsed.value;
    } catch {
      return null;
    }
  }

  remove(key: string): void {
    localStorage.removeItem(this.getKey(key));
  }

  clear(): void {
    Object.keys(localStorage)
      .filter(key => key.startsWith(this.prefix))
      .forEach(key => localStorage.removeItem(key));
  }

  getAll<T>(): StorageItem<T>[] {
    return Object.keys(localStorage)
      .filter(key => key.startsWith(this.prefix))
      .map(key => {
        try {
          return JSON.parse(localStorage.getItem(key)!) as StorageItem<T>;
        } catch {
          return null;
        }
      })
      .filter((item): item is StorageItem<T> => item !== null);
  }

  has(key: string): boolean {
    return localStorage.getItem(this.getKey(key)) !== null;
  }

  getSize(): number {
    return Object.keys(localStorage)
      .filter(key => key.startsWith(this.prefix))
      .reduce((size, key) => size + localStorage.getItem(key)!.length, 0);
  }
}

// Type-safe local storage with expiration
class ExpiringLocalStorage extends LocalStorageManager {
  setWithExpiry<T>(key: string, value: T, expiryInMinutes: number): void {
    const item = {
      value,
      expiry: Date.now() + expiryInMinutes * 60 * 1000
    };
    this.set(key, item);
  }

  getWithExpiry<T>(key: string): T | null {
    const item = this.get<{ value: T; expiry: number }>(key);
    if (!item) return null;

    if (Date.now() > item.expiry) {
      this.remove(key);
      return null;
    }

    return item.value;
  }
}

// Type-safe local storage with encryption
class EncryptedLocalStorage extends LocalStorageManager {
  private encryptionKey: string;

  constructor(prefix: string, encryptionKey: string) {
    super(prefix);
    this.encryptionKey = encryptionKey;
  }

  private encrypt(data: string): string {
    // Implementation of encryption
    return data;
  }

  private decrypt(data: string): string {
    // Implementation of decryption
    return data;
  }

  set<T>(key: string, value: T): void {
    const encrypted = this.encrypt(JSON.stringify(value));
    super.set(key, encrypted);
  }

  get<T>(key: string): T | null {
    const encrypted = super.get<string>(key);
    if (!encrypted) return null;

    try {
      return JSON.parse(this.decrypt(encrypted)) as T;
    } catch {
      return null;
    }
  }
}

28. Session Storage

Understanding TypeScript's session storage features.

// Session storage types with type safety
interface SessionItem<T> {
  key: string;
  value: T;
  timestamp: number;
}

// Type-safe session storage manager
class SessionStorageManager {
  private prefix: string;

  constructor(prefix: string = "app_") {
    this.prefix = prefix;
  }

  private getKey(key: string): string {
    return `${this.prefix}${key}`;
  }

  set<T>(key: string, value: T): void {
    const item: SessionItem<T> = {
      key,
      value,
      timestamp: Date.now()
    };
    sessionStorage.setItem(this.getKey(key), JSON.stringify(item));
  }

  get<T>(key: string): T | null {
    const item = sessionStorage.getItem(this.getKey(key));
    if (!item) return null;

    try {
      const parsed = JSON.parse(item) as SessionItem<T>;
      return parsed.value;
    } catch {
      return null;
    }
  }

  remove(key: string): void {
    sessionStorage.removeItem(this.getKey(key));
  }

  clear(): void {
    Object.keys(sessionStorage)
      .filter(key => key.startsWith(this.prefix))
      .forEach(key => sessionStorage.removeItem(key));
  }

  getAll<T>(): SessionItem<T>[] {
    return Object.keys(sessionStorage)
      .filter(key => key.startsWith(this.prefix))
      .map(key => {
        try {
          return JSON.parse(sessionStorage.getItem(key)!) as SessionItem<T>;
        } catch {
          return null;
        }
      })
      .filter((item): item is SessionItem<T> => item !== null);
  }

  has(key: string): boolean {
    return sessionStorage.getItem(this.getKey(key)) !== null;
  }

  getSize(): number {
    return Object.keys(sessionStorage)
      .filter(key => key.startsWith(this.prefix))
      .reduce((size, key) => size + sessionStorage.getItem(key)!.length, 0);
  }
}

// Type-safe session storage with tab isolation
class TabIsolatedSessionStorage extends SessionStorageManager {
  private tabId: string;

  constructor(prefix: string) {
    super(prefix);
    this.tabId = this.generateTabId();
  }

  private generateTabId(): string {
    return Math.random().toString(36).substring(2);
  }

  private getTabKey(key: string): string {
    return `${this.tabId}_${key}`;
  }

  set<T>(key: string, value: T): void {
    super.set(this.getTabKey(key), value);
  }

  get<T>(key: string): T | null {
    return super.get<T>(this.getTabKey(key));
  }

  remove(key: string): void {
    super.remove(this.getTabKey(key));
  }
}

// Type-safe session storage with encryption
class EncryptedSessionStorage extends SessionStorageManager {
  private encryptionKey: string;

  constructor(prefix: string, encryptionKey: string) {
    super(prefix);
    this.encryptionKey = encryptionKey;
  }

  private encrypt(data: string): string {
    // Implementation of encryption
    return data;
  }

  private decrypt(data: string): string {
    // Implementation of decryption
    return data;
  }

  set<T>(key: string, value: T): void {
    const encrypted = this.encrypt(JSON.stringify(value));
    super.set(key, encrypted);
  }

  get<T>(key: string): T | null {
    const encrypted = super.get<string>(key);
    if (!encrypted) return null;

    try {
      return JSON.parse(this.decrypt(encrypted)) as T;
    } catch {
      return null;
    }
  }
}

29. Cookies

Understanding TypeScript's cookie handling features.

// Cookie types with type safety
interface CookieOptions {
  expires?: Date;
  path?: string;
  domain?: string;
  secure?: boolean;
  sameSite?: "strict" | "lax" | "none";
}

interface CookieItem<T> {
  key: string;
  value: T;
  options?: CookieOptions;
}

// Type-safe cookie manager
class CookieManager {
  private prefix: string;

  constructor(prefix: string = "app_") {
    this.prefix = prefix;
  }

  private getKey(key: string): string {
    return `${this.prefix}${key}`;
  }

  set<T>(key: string, value: T, options?: CookieOptions): void {
    const cookieValue = JSON.stringify(value);
    const cookieOptions = this.buildCookieOptions(options);
    document.cookie = `${this.getKey(key)}=${encodeURIComponent(cookieValue)}${cookieOptions}`;
  }

  get<T>(key: string): T | null {
    const cookies = this.parseCookies();
    const cookie = cookies[this.getKey(key)];
    if (!cookie) return null;

    try {
      return JSON.parse(decodeURIComponent(cookie)) as T;
    } catch {
      return null;
    }
  }

  remove(key: string): void {
    this.set(key, "", { expires: new Date(0) });
  }

  private buildCookieOptions(options?: CookieOptions): string {
    if (!options) return "";

    const parts: string[] = [];

    if (options.expires) {
      parts.push(`expires=${options.expires.toUTCString()}`);
    }

    if (options.path) {
      parts.push(`path=${options.path}`);
    }

    if (options.domain) {
      parts.push(`domain=${options.domain}`);
    }

    if (options.secure) {
      parts.push("secure");
    }

    if (options.sameSite) {
      parts.push(`samesite=${options.sameSite}`);
    }

    return parts.length ? `; ${parts.join("; ")}` : "";
  }

  private parseCookies(): Record<string, string> {
    return document.cookie.split("; ").reduce((cookies, cookie) => {
      const [key, value] = cookie.split("=");
      cookies[key] = value;
      return cookies;
    }, {} as Record<string, string>);
  }
}

// Type-safe cookie with expiration
class ExpiringCookieManager extends CookieManager {
  setWithExpiry<T>(key: string, value: T, expiryInDays: number): void {
    const expires = new Date();
    expires.setDate(expires.getDate() + expiryInDays);
    this.set(key, value, { expires });
  }
}

// Type-safe cookie with encryption
class EncryptedCookieManager extends CookieManager {
  private encryptionKey: string;

  constructor(prefix: string, encryptionKey: string) {
    super(prefix);
    this.encryptionKey = encryptionKey;
  }

  private encrypt(data: string): string {
    // Implementation of encryption
    return data;
  }

  private decrypt(data: string): string {
    // Implementation of decryption
    return data;
  }

  set<T>(key: string, value: T, options?: CookieOptions): void {
    const encrypted = this.encrypt(JSON.stringify(value));
    super.set(key, encrypted, options);
  }

  get<T>(key: string): T | null {
    const encrypted = super.get<string>(key);
    if (!encrypted) return null;

    try {
      return JSON.parse(this.decrypt(encrypted)) as T;
    } catch {
      return null;
    }
  }
}

30. Web Workers

Understanding TypeScript's web worker features.

// Web worker types with type safety
interface WorkerMessage<T> {
  type: string;
  payload: T;
}

interface WorkerResponse<T> {
  type: string;
  payload: T;
  error?: string;
}

// Type-safe web worker manager
class WorkerManager {
  private worker: Worker;
  private messageHandlers: Map<string, (payload: unknown) => Promise<unknown>>;

  constructor(workerScript: string) {
    this.worker = new Worker(workerScript);
    this.messageHandlers = new Map();
    this.setupMessageListener();
  }

  private setupMessageListener(): void {
    this.worker.onmessage = (event: MessageEvent<WorkerResponse<unknown>>) => {
      const { type, payload, error } = event.data;
      if (error) {
        console.error(`Worker error: ${error}`);
        return;
      }

      const handler = this.messageHandlers.get(type);
      if (handler) {
        handler(payload);
      }
    };
  }

  registerHandler<T, R>(
    type: string,
    handler: (payload: T) => Promise<R>
  ): void {
    this.messageHandlers.set(type, handler as (payload: unknown) => Promise<unknown>);
  }

  postMessage<T>(message: WorkerMessage<T>): void {
    this.worker.postMessage(message);
  }

  terminate(): void {
    this.worker.terminate();
  }
}

// Type-safe web worker implementation
class DataProcessingWorker {
  private worker: Worker;

  constructor() {
    this.worker = new Worker("data-processing.worker.js");
  }

  async processData<T>(data: T[]): Promise<T[]> {
    return new Promise((resolve, reject) => {
      const messageHandler = (event: MessageEvent<WorkerResponse<T[]>>) => {
        const { payload, error } = event.data;
        if (error) {
          reject(new Error(error));
          return;
        }
        resolve(payload);
      };

      this.worker.onmessage = messageHandler;
      this.worker.postMessage({ type: "process", payload: data });
    });
  }

  terminate(): void {
    this.worker.terminate();
  }
}

// Type-safe web worker pool
class WorkerPool {
  private workers: Worker[];
  private currentIndex: number;

  constructor(workerScript: string, poolSize: number) {
    this.workers = Array.from({ length: poolSize }, () => new Worker(workerScript));
    this.currentIndex = 0;
  }

  async executeTask<T, R>(task: T): Promise<R> {
    const worker = this.getNextWorker();
    return new Promise((resolve, reject) => {
      const messageHandler = (event: MessageEvent<WorkerResponse<R>>) => {
        const { payload, error } = event.data;
        if (error) {
          reject(new Error(error));
          return;
        }
        resolve(payload);
      };

      worker.onmessage = messageHandler;
      worker.postMessage({ type: "task", payload: task });
    });
  }

  private getNextWorker(): Worker {
    const worker = this.workers[this.currentIndex];
    this.currentIndex = (this.currentIndex + 1) % this.workers.length;
    return worker;
  }

  terminate(): void {
    this.workers.forEach(worker => worker.terminate());
  }
}

// Type-safe web worker with shared memory
class SharedMemoryWorker {
  private worker: Worker;
  private sharedBuffer: SharedArrayBuffer;
  private sharedArray: Int32Array;

  constructor(workerScript: string, bufferSize: number) {
    this.worker = new Worker(workerScript);
    this.sharedBuffer = new SharedArrayBuffer(bufferSize);
    this.sharedArray = new Int32Array(this.sharedBuffer);
  }

  async processData<T>(data: T[]): Promise<T[]> {
    return new Promise((resolve, reject) => {
      const messageHandler = (event: MessageEvent<WorkerResponse<T[]>>) => {
        const { payload, error } = event.data;
        if (error) {
          reject(new Error(error));
          return;
        }
        resolve(payload);
      };

      this.worker.onmessage = messageHandler;
      this.worker.postMessage({
        type: "process",
        payload: data,
        sharedBuffer: this.sharedBuffer
      });
    });
  }

  getSharedArray(): Int32Array {
    return this.sharedArray;
  }

  terminate(): void {
    this.worker.terminate();
  }
}

31. Service Workers

Understanding TypeScript's service worker features.

// Service worker types with type safety
interface ServiceWorkerMessage<T> {
  type: string;
  payload: T;
}

interface ServiceWorkerResponse<T> {
  type: string;
  payload: T;
  error?: string;
}

// Type-safe service worker registration
class ServiceWorkerManager {
  private registration: ServiceWorkerRegistration | null = null;

  async register(scriptURL: string, options?: RegistrationOptions): Promise<void> {
    if ("serviceWorker" in navigator) {
      try {
        this.registration = await navigator.serviceWorker.register(scriptURL, options);
        console.log("Service Worker registered successfully");
      } catch (error) {
        console.error("Service Worker registration failed:", error);
        throw error;
      }
    }
  }

  async unregister(): Promise<boolean> {
    if (this.registration) {
      return await this.registration.unregister();
    }
    return false;
  }

  async update(): Promise<void> {
    if (this.registration) {
      await this.registration.update();
    }
  }
}

// Type-safe service worker cache manager
class CacheManager {
  private cacheName: string;

  constructor(cacheName: string) {
    this.cacheName = cacheName;
  }

  async addToCache(request: Request, response: Response): Promise<void> {
    const cache = await caches.open(this.cacheName);
    await cache.put(request, response);
  }

  async getFromCache(request: Request): Promise<Response | undefined> {
    const cache = await caches.open(this.cacheName);
    return await cache.match(request);
  }

  async deleteFromCache(request: Request): Promise<boolean> {
    const cache = await caches.open(this.cacheName);
    return await cache.delete(request);
  }

  async clearCache(): Promise<void> {
    await caches.delete(this.cacheName);
  }
}

// Type-safe service worker message handler
class ServiceWorkerMessageHandler {
  private handlers: Map<string, (payload: unknown) => Promise<unknown>>;

  constructor() {
    this.handlers = new Map();
  }

  registerHandler<T, R>(
    type: string,
    handler: (payload: T) => Promise<R>
  ): void {
    this.handlers.set(type, handler as (payload: unknown) => Promise<unknown>);
  }

  async handleMessage<T, R>(
    message: ServiceWorkerMessage<T>
  ): Promise<ServiceWorkerResponse<R>> {
    const handler = this.handlers.get(message.type);
    if (!handler) {
      return {
        type: message.type,
        payload: null as unknown as R,
        error: "No handler registered for this message type"
      };
    }

    try {
      const result = await handler(message.payload);
      return {
        type: message.type,
        payload: result as R
      };
    } catch (error) {
      return {
        type: message.type,
        payload: null as unknown as R,
        error: error instanceof Error ? error.message : "Unknown error"
      };
    }
  }
}

// Type-safe service worker background sync
class BackgroundSyncManager {
  private registration: ServiceWorkerRegistration;

  constructor(registration: ServiceWorkerRegistration) {
    this.registration = registration;
  }

  async registerSync(tag: string): Promise<void> {
    if ("sync" in this.registration) {
      await this.registration.sync.register(tag);
    }
  }

  async getTags(): Promise<string[]> {
    if ("sync" in this.registration) {
      return await this.registration.sync.getTags();
    }
    return [];
  }
}

// Type-safe service worker push notification
class PushNotificationManager {
  private registration: ServiceWorkerRegistration;

  constructor(registration: ServiceWorkerRegistration) {
    this.registration = registration;
  }

  async subscribeToPush(
    applicationServerKey: string
  ): Promise<PushSubscription | null> {
    try {
      const subscription = await this.registration.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey
      });
      return subscription;
    } catch (error) {
      console.error("Failed to subscribe to push notifications:", error);
      return null;
    }
  }

  async unsubscribeFromPush(): Promise<boolean> {
    const subscription = await this.registration.pushManager.getSubscription();
    if (subscription) {
      return await subscription.unsubscribe();
    }
    return false;
  }
}

32. Web Sockets

Understanding TypeScript's web socket features.

// WebSocket types with type safety
interface WebSocketMessage<T> {
  type: string;
  payload: T;
}

interface WebSocketResponse<T> {
  type: string;
  payload: T;
  error?: string;
}

// Type-safe WebSocket manager
class WebSocketManager {
  private socket: WebSocket | null = null;
  private messageHandlers: Map<string, (payload: unknown) => void>;
  private reconnectAttempts: number = 0;
  private maxReconnectAttempts: number = 5;
  private reconnectDelay: number = 1000;

  constructor(private url: string) {
    this.messageHandlers = new Map();
  }

  connect(): void {
    this.socket = new WebSocket(this.url);
    this.setupEventListeners();
  }

  private setupEventListeners(): void {
    if (!this.socket) return;

    this.socket.onopen = () => {
      console.log("WebSocket connected");
      this.reconnectAttempts = 0;
    };

    this.socket.onmessage = (event: MessageEvent) => {
      try {
        const message = JSON.parse(event.data) as WebSocketMessage<unknown>;
        const handler = this.messageHandlers.get(message.type);
        if (handler) {
          handler(message.payload);
        }
      } catch (error) {
        console.error("Failed to parse WebSocket message:", error);
      }
    };

    this.socket.onclose = () => {
      console.log("WebSocket disconnected");
      this.attemptReconnect();
    };

    this.socket.onerror = (error) => {
      console.error("WebSocket error:", error);
    };
  }

  private attemptReconnect(): void {
    if (this.reconnectAttempts < this.maxReconnectAttempts) {
      this.reconnectAttempts++;
      setTimeout(() => {
        console.log(`Attempting to reconnect (attempt ${this.reconnectAttempts})`);
        this.connect();
      }, this.reconnectDelay * this.reconnectAttempts);
    }
  }

  registerHandler<T>(
    type: string,
    handler: (payload: T) => void
  ): void {
    this.messageHandlers.set(type, handler as (payload: unknown) => void);
  }

  send<T>(message: WebSocketMessage<T>): void {
    if (this.socket?.readyState === WebSocket.OPEN) {
      this.socket.send(JSON.stringify(message));
    } else {
      console.error("WebSocket is not connected");
    }
  }

  close(): void {
    if (this.socket) {
      this.socket.close();
      this.socket = null;
    }
  }
}

// Type-safe WebSocket with authentication
class AuthenticatedWebSocket extends WebSocketManager {
  private token: string;

  constructor(url: string, token: string) {
    super(url);
    this.token = token;
  }

  connect(): void {
    const urlWithToken = `${this.url}?token=${this.token}`;
    super.connect();
  }
}

// Type-safe WebSocket with heartbeat
class HeartbeatWebSocket extends WebSocketManager {
  private heartbeatInterval: number = 30000;
  private heartbeatTimer: NodeJS.Timeout | null = null;

  connect(): void {
    super.connect();
    this.startHeartbeat();
  }

  private startHeartbeat(): void {
    this.heartbeatTimer = setInterval(() => {
      this.send({ type: "heartbeat", payload: { timestamp: Date.now() } });
    }, this.heartbeatInterval);
  }

  close(): void {
    if (this.heartbeatTimer) {
      clearInterval(this.heartbeatTimer);
      this.heartbeatTimer = null;
    }
    super.close();
  }
}

// Type-safe WebSocket with message queue
class QueuedWebSocket extends WebSocketManager {
  private messageQueue: WebSocketMessage<unknown>[] = [];

  send<T>(message: WebSocketMessage<T>): void {
    if (this.socket?.readyState === WebSocket.OPEN) {
      super.send(message);
    } else {
      this.messageQueue.push(message);
    }
  }

  private setupEventListeners(): void {
    super.setupEventListeners();
    if (this.socket) {
      this.socket.onopen = () => {
        console.log("WebSocket connected");
        this.flushMessageQueue();
      };
    }
  }

  private flushMessageQueue(): void {
    while (this.messageQueue.length > 0) {
      const message = this.messageQueue.shift();
      if (message) {
        super.send(message);
      }
    }
  }
}