TypeScript generic stack and queue

Write containers that work for any element type and keep it checked.

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());
Output
results search 2
10 20 1
30 undefined

Explanation

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.

A stack is last-in, first-out and an array supports it with push and pop in O(1). A queue is first-in, first-out. Removing from the front of an array with shift is O(n), so this queue keeps a head index and reads from it, giving O(1) dequeue. Both classes expose a size and never leak the internal array.

Explore the dry run
Guided walkthroughReady
1class Stack<T> {
2 private items: T[] = [];
3
4 push(item: T): void {
5 this.items.push(item);
6 }
7
8 pop(): T | undefined {
9 return this.items.pop();
10 }
11
12 peek(): T | undefined {
13 return this.items[this.items.length - 1];
14 }
15
16 get size(): number {
17 return this.items.length;
18 }
19}
20
21class Queue<T> {
22 private items: T[] = [];
23 private head = 0;
24
25 enqueue(item: T): void {
26 this.items.push(item);
27 }
28
29 dequeue(): T | undefined {
30 if (this.head >= this.items.length) {
31 return undefined;
32 }
33 return this.items[this.head++];
34 }
35
36 get size(): number {
37 return this.items.length - this.head;
38 }
39}
40
41const history = new Stack<string>();
42history.push("home");
43history.push("search");
44history.push("results");
45console.log(history.pop(), history.peek(), history.size);
46
47const jobs = new Queue<number>();
48[10, 20, 30].forEach((job) => jobs.enqueue(job));
49console.log(jobs.dequeue(), jobs.dequeue(), jobs.size);
50console.log(jobs.dequeue(), jobs.dequeue());

Follow the example

Start to inspect the source, values, and output. These prepared steps explain the published sample; grouped loop steps describe multiple iterations.

View the complete dry-run table
Prepared trace of the published program. Some rows group repeated iterations.
Step / lineWhat happensState after stepOutput so far
T is filled in by the user: Stack<string> holds strings only.—
—
The return type forces callers to consider the empty stack.—
—
Dequeue reads at the head and moves it forward, in O(1).—
—
The last page visited is removed first; search is now on top.—
results search 2
The oldest jobs come out first.—
results search 2
10 20 1
The third call returns 30 and the fourth finds the queue empty.—
results search 2
10 20 1
30 undefined

Cost and common mistakes

push, pop, peek, enqueue, and dequeue are all O(1).

  • The queue's array keeps consumed items. A real implementation compacts it occasionally or uses a linked list.
  • T | undefined makes an empty result visible, but a Stack<undefined> would be ambiguous. Avoid storing undefined.
  • Generics are erased at run time. You cannot test x instanceof T.

Try it yourself

What does history.push(42) do?

Reveal answer and reasoning

It is a compile-time error, because history is a Stack<string> and 42 is a number.

Further reading