TypeScript generic stack and queue

A generic class takes a type parameter, so Stack<number> and Stack<string> share one implementation but cannot be mixed up. The compiler knows that pop returns a T | undefined, so you must handle the empty case before using the value. The type parameter exists only at compile time.

TypeScript
class Stack<T> {
  private items: T[] = [];

  push(item: T): void {
    this.items.push(item);
  }

  pop(): T | undefined {
    return this.items.pop();
  }

  peek(): T | undefined {
    return this.items[this.items.length - 1];
  }

  get size(): number {
    return this.items.length;
  }
}

class Queue<T> {
  private items: T[] = [];
  private head = 0;

  enqueue(item: T): void {
    this.items.push(item);
  }

  dequeue(): T | undefined {
    if (this.head >= this.items.length) {
      return undefined;
    }
    return this.items[this.head++];
  }

  get size(): number {
    return this.items.length - this.head;
  }
}

const history = new Stack<string>();
history.push("home");
history.push("search");
history.push("results");
console.log(history.pop(), history.peek(), history.size);

const jobs = new Queue<number>();
[10, 20, 30].forEach((job) => jobs.enqueue(job));
console.log(jobs.dequeue(), jobs.dequeue(), jobs.size);
console.log(jobs.dequeue(), jobs.dequeue());
Read the full lesson