class Deque<T> { private items: T[] = []; addFront(element: T) { this.items.unshift(element); } addBack(element: T) { this.items.push(element); } removeFront(): T | undefined { return this.items.shift(); } removeBack(): T | undefined { return this.items.pop(); } print(): string { return this.items.join(' -> ') + ' -> null'; } } const deque = new Deque<number>(); deque.addBack(10); deque.addFront(20); deque.addBack(30); deque.removeFront(); deque.addFront(40); console.log(deque.print());
The deque starts empty.
addBack(10) adds 10 at back: [10]
addFront(20) adds 20 at front: [20, 10]
addBack(30) adds 30 at back: [20, 10, 30]
removeFront() removes 20: [10, 30]
addFront(40) adds 40 at front: [40, 10, 30]
Printed state is "40 -> 10 -> 30 -> null".
Start empty.
addBack(5): [5]
addFront(3): [3, 5]
removeBack(): removes 5, now [3]
addBack(7): [3, 7]
removeFront(): removes 3, now [7]
Only one item remains.
class Deque<T> { private items: T[] = []; removeFront(): T { return this.items.shift()!; } } const deque = new Deque<number>(); console.log(deque.removeFront());
Calling shift() on an empty array returns undefined.
The non-null assertion operator (!) only affects TypeScript's type checking and is erased at runtime.
Therefore, undefined is returned without error, and console.log prints 'undefined'.
class Deque<T> { private items: T[] = []; addFront(element: T) { this.items.unshift(element); } addBack(element: T) { this.items.push(element); } removeFront(): T | undefined { return this.items.shift(); } removeBack(): T | undefined { return this.items.pop(); } print(): string { return this.items.join(' -> ') + ' -> null'; } } const deque = new Deque<string>(); deque.addBack('a'); deque.addBack('b'); deque.addFront('c'); deque.removeBack(); deque.addFront('d'); deque.removeFront(); console.log(deque.print());
Start empty.
addBack('a'): [a]
addBack('b'): [a, b]
addFront('c'): [c, a, b]
removeBack(): removes 'b', now [c, a]
addFront('d'): [d, c, a]
removeFront(): removes 'd', now [c, a]
Printed state: "c -> a -> null".
Without synchronization, concurrent modifications can overlap.
This causes race conditions where the deque's internal state becomes inconsistent or corrupted.
Deadlocks require locks, which are not mentioned here.
Memory leaks or stack overflow are unrelated to concurrent unsynchronized access.
