Table of contents
Open Table of contents
- 1. Array
- 2. Object (Key–Value)
- 3. Map
- 4. Set
- 5. Boolean Operators
- 6. Comparison Operators
- 7. Stack (LIFO)
- 8. Queue (FIFO)
- 9. Dictionary Pattern
- 10. Tuple
- 11. Destructuring
- 12. Spread / Rest
- 13. Optional Chaining
- 14. JSON
- 15. Common Patterns
- Deduplicate Array (see primitive)
- Deduplicate Array (object by key)
- Index Array by Key
- Partition Array
- Chunk Array
- Flatten Array (1 level)
- Remove Falsy Values
- Toggle Value in Array
- Intersection of Arrays
- Difference of Arrays
- Union of Arrays
- Pick Object Properties
- Omit Object Properties
- Group + Sum
- Find Max by Property
- 16. Priority Queue (Min / Max Heap)
- 17. Deque (Double-Ended Queue)
- 18. Linked List (Singly)
- 19. Binary Tree
- 20. DFS (Tree Traversal)
- 21. BFS (Queue)
- 22. Trie (Prefix Tree)
- 23. Union Find (Disjoint Set)
- 24. LRU Cache
- 25. Async Queue (Concurrency Control)
- 26. Memoization
- 27. Event Emitter
- 28. Type-Safe Enum Pattern
- 29. Discriminated Union
- 30. Result / Either Pattern
1. Array
const arr: number[] = [1, 2, 3];
// Add / Remove
arr.push(4);
arr.pop();
arr.unshift(0);
arr.shift();
// Access
const first: number = arr[0];
const last: number | undefined = arr.at(-1);
Common Array Manipulation
const nums: number[] = [1, 2, 3, 4];
// map
const doubled: number[] = nums.map(n => n * 2);
// filter
const evens: number[] = nums.filter(n => n % 2 === 0);
// reduce
const sum: number = nums.reduce((acc, n) => acc + n, 0);
// find
const found: number | undefined = nums.find(n => n > 2);
// some / every
const hasLarge: boolean = nums.some(n => n > 3);
const allPositive: boolean = nums.every(n => n > 0);
// includes
const hasTwo: boolean = nums.includes(2);
2. Object (Key–Value)
type User = {
id: number;
name: string;
age?: number;
};
const user: User = {
id: 1,
name: "Huy",
};
// Access
const username: string = user.name;
// Add / Update
user.age = 25;
// Delete (optional only)
delete user.age;
// Iterate
Object.keys(user); // string[]
Object.values(user); // (string | number)[]
Object.entries(user); // [string, string | number][]
3. Map
const map = new Map<string, number | string>();
map.set("id", 1);
map.set("name", "Huy");
const name: string | number | undefined = map.get("name");
map.has("id"); // boolean
map.delete("id");
for (const [key, value] of map) {
console.log(key, value);
}
4. Set
const set: Set<number> = new Set([1, 2, 2, 3]);
set.add(4);
set.delete(2);
set.has(3);
const unique: number[] = [...set];
5. Boolean Operators
const a: boolean = true;
const b: boolean = false;
a && b;
a || b;
!a;
Short-circuit
const name: string = input || "default";
isAdmin && doSomething();
Nullish Coalescing
const value: string = data ?? "fallback";
6. Comparison Operators
1 == "1"; // boolean
1 === "1"; // boolean (false)
7. Stack (LIFO)
class Stack<T> {
private items: T[] = [];
push(item: T): void {
this.items.push(item);
}
pop(): T | undefined {
return this.items.pop();
}
}
const stack = new Stack<number>();
stack.push(1);
stack.push(2);
stack.pop();
8. Queue (FIFO)
class Queue<T> {
private items: T[] = [];
enqueue(item: T): void {
this.items.push(item);
}
dequeue(): T | undefined {
return this.items.shift();
}
}
const queue = new Queue<number>();
queue.enqueue(1);
queue.enqueue(2);
queue.dequeue();
9. Dictionary Pattern
type Dict<T> = Record<string, T>;
const dict: Dict<number> = {};
dict["a"] = 1;
dict["b"] = 2;
10. Tuple
const point: [number, number] = [10, 20];
const [x, y] = point;
11. Destructuring
const user = {name: "Huy", age: 25};
const {name, age} = user;
const arr2: number[] = [1, 2];
const [a1, b1] = arr2;
12. Spread / Rest
const a1: number[] = [1, 2];
const b1: number[] = [...a1, 3];
const obj = {x: 1};
const copy = {...obj, y: 2};
function sum(...nums: number[]): number {
return nums.reduce((a, b) => a + b, 0);
}
13. Optional Chaining
type Profile = {
email?: string;
};
type User = {
profile?: Profile;
};
user.profile?.email;
14. JSON
const json: string = JSON.stringify({a: 1});
const parsed: { a: number } = JSON.parse(json);
15. Common Patterns
Deduplicate Array (see primitive)
const nums = [1, 2, 2, 3, 3];
const unique = [...new Set(nums)];
Input
[1, 2, 2, 3, 3]
Output
[1, 2, 3]
Deduplicate Array (object by key)
type User = { id: number; name: string };
const users: User[] = [
{ id: 1, name: "A" },
{ id: 1, name: "A" },
{ id: 2, name: "B" },
];
const unique = Object.values(
users.reduce<Record<number, User>>((acc, cur) => {
acc[cur.id] = cur;
return acc;
}, {})
);
Input
[
{ id: 1, name: "A" },
{ id: 1, name: "A" },
{ id: 2, name: "B" }
]
Output
[
{ id: 1, name: "A" },
{ id: 2, name: "B" }
]
Index Array by Key
type User = { id: number; name: string };
const users: User[] = [
{ id: 1, name: "A" },
{ id: 2, name: "B" },
];
const byId = users.reduce<Record<number, User>>((acc, cur) => {
acc[cur.id] = cur;
return acc;
}, {});
Input
[
{ id: 1, name: "A" },
{ id: 2, name: "B" }
]
Output
{
1: { id: 1, name: "A" },
2: { id: 2, name: "B" }
}
Partition Array
const nums = [1, 2, 3, 4, 5];
const [even, odd] = nums.reduce<[number[], number[]]>(
(acc, cur) => {
acc[cur % 2 === 0 ? 0 : 1].push(cur);
return acc;
},
[[], []]
);
Input
[1, 2, 3, 4, 5]
Output
even = [2, 4]
odd = [1, 3, 5]
Chunk Array
function chunk<T>(arr: T[], size: number): T[][] {
return arr.reduce<T[][]>((acc, cur, i) => {
if (i % size === 0) acc.push([]);
acc[acc.length - 1].push(cur);
return acc;
}, []);
}
chunk([1, 2, 3, 4, 5], 2);
Input
([1, 2, 3, 4, 5], 2)
Output
[[1, 2], [3, 4], [5]]
Flatten Array (1 level)
const arr = [[1], [2, 3], [4]];
const flat = arr.reduce<number[]>((acc, cur) => acc.concat(cur), []);
Input
[[1], [2, 3], [4]]
Output
[1, 2, 3, 4]
Remove Falsy Values
const values = [0, 1, false, "", null, undefined, "ok"];
const truthy = values.filter(Boolean);
Input
[0, 1, false, "", null, undefined, "ok"]
Output
[1, "ok"]
Toggle Value in Array
function toggle<T>(arr: T[], value: T): T[] {
return arr.includes(value)
? arr.filter(v => v !== value)
: [...arr, value];
}
toggle([1, 2, 3], 2);
Input
([1, 2, 3], 2)
Output
[1, 3]
Intersection of Arrays
const a = [1, 2, 3];
const b = [2, 3, 4];
const intersection = a.filter(v => b.includes(v));
Input
[1, 2, 3], [2, 3, 4]
Output
[2, 3]
Difference of Arrays
const a = [1, 2, 3];
const b = [2];
const diff = a.filter(v => !b.includes(v));
Input
[1, 2, 3], [2]
Output
[1, 3]
Union of Arrays
const a = [1, 2];
const b = [2, 3];
const union = [...new Set([...a, ...b])];
Input
[1, 2], [2, 3]
Output
[1, 2, 3]
Pick Object Properties
function pick<T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {
return keys.reduce((acc, key) => {
acc[key] = obj[key];
return acc;
}, {} as Pick<T, K>);
}
pick({ a: 1, b: 2, c: 3 }, ["a", "c"]);
Input
{ a: 1, b: 2, c: 3 }, ["a", "c"]
Output
{ a: 1, c: 3 }
Omit Object Properties
function omit<T, K extends keyof T>(obj: T, keys: K[]): Omit<T, K> {
const clone = { ...obj };
keys.forEach(k => delete clone[k]);
return clone;
}
omit({ a: 1, b: 2, c: 3 }, ["b"]);
Input
{ a: 1, b: 2, c: 3 }, ["b"]
Output
{ a: 1, c: 3 }
Group + Sum
type Item = { type: string; amount: number };
const items: Item[] = [
{ type: "A", amount: 10 },
{ type: "B", amount: 5 },
{ type: "A", amount: 7 },
];
const totalByType = items.reduce<Record<string, number>>((acc, cur) => {
acc[cur.type] = (acc[cur.type] ?? 0) + cur.amount;
return acc;
}, {});
Input
[
{ type: "A", amount: 10 },
{ type: "B", amount: 5 },
{ type: "A", amount: 7 }
]
Output
{ A: 17, B: 5 }
Find Max by Property
type Item = { score: number };
const items: Item[] = [
{ score: 10 },
{ score: 30 },
{ score: 20 },
];
const max = items.reduce((a, b) => (a.score > b.score ? a : b));
Input
[{ score: 10 }, { score: 30 }, { score: 20 }]
Output
{ score: 30 }
16. Priority Queue (Min / Max Heap)
class PriorityQueue<T> {
private heap: T[] = [];
constructor(private compare: (a: T, b: T) => boolean) {}
push(item: T): void {
this.heap.push(item);
this.bubbleUp();
}
pop(): T | undefined {
if (this.heap.length === 1) return this.heap.pop();
const top = this.heap[0];
this.heap[0] = this.heap.pop()!;
this.bubbleDown();
return top;
}
private bubbleUp() {
let i = this.heap.length - 1;
while (i > 0) {
const p = Math.floor((i - 1) / 2);
if (!this.compare(this.heap[i], this.heap[p])) break;
[this.heap[i], this.heap[p]] = [this.heap[p], this.heap[i]];
i = p;
}
}
private bubbleDown() {
let i = 0;
while (true) {
let l = i * 2 + 1;
let r = i * 2 + 2;
let best = i;
if (l < this.heap.length && this.compare(this.heap[l], this.heap[best])) best = l;
if (r < this.heap.length && this.compare(this.heap[r], this.heap[best])) best = r;
if (best === i) break;
[this.heap[i], this.heap[best]] = [this.heap[best], this.heap[i]];
i = best;
}
}
}
Min Heap
const pq = new PriorityQueue<number>((a, b) => a < b);
pq.push(3);
pq.push(1);
pq.push(2);
pq.pop();
Output
1
17. Deque (Double-Ended Queue)
class Deque<T> {
private data: T[] = [];
pushFront(v: T) { this.data.unshift(v); }
pushBack(v: T) { this.data.push(v); }
popFront(): T | undefined { return this.data.shift(); }
popBack(): T | undefined { return this.data.pop(); }
}
const d = new Deque<number>();
d.pushBack(1);
d.pushFront(0);
d.popFront();
Output
0
18. Linked List (Singly)
class ListNode<T> {
constructor(public val: T, public next?: ListNode<T>) {}
}
const head = new ListNode(1, new ListNode(2, new ListNode(3)));
head.next?.val;
Output
2
19. Binary Tree
class TreeNode {
constructor(
public val: number,
public left?: TreeNode,
public right?: TreeNode
) {}
}
const root = new TreeNode(
1,
new TreeNode(2),
new TreeNode(3)
);
20. DFS (Tree Traversal)
function dfs(node?: TreeNode): void {
if (!node) return;
console.log(node.val);
dfs(node.left);
dfs(node.right);
}
dfs(root);
Output
1
2
3
21. BFS (Queue)
const queue: TreeNode[] = [root];
while (queue.length) {
const node = queue.shift()!;
console.log(node.val);
node.left && queue.push(node.left);
node.right && queue.push(node.right);
}
Output
1
2
3
22. Trie (Prefix Tree)
class Trie {
children = new Map<string, Trie>();
end = false;
insert(word: string) {
let node: Trie = this;
for (const ch of word) {
if (!node.children.has(ch)) {
node.children.set(ch, new Trie());
}
node = node.children.get(ch)!;
}
node.end = true;
}
search(word: string): boolean {
let node: Trie | undefined = this;
for (const ch of word) {
node = node.children.get(ch);
if (!node) return false;
}
return node.end;
}
}
const trie = new Trie();
trie.insert("go");
trie.search("go");
Output
true
23. Union Find (Disjoint Set)
class UnionFind {
parent: number[];
constructor(n: number) {
this.parent = Array.from({ length: n }, (_, i) => i);
}
find(x: number): number {
if (this.parent[x] !== x) {
this.parent[x] = this.find(this.parent[x]);
}
return this.parent[x];
}
union(a: number, b: number): void {
this.parent[this.find(a)] = this.find(b);
}
}
const uf = new UnionFind(3);
uf.union(0, 1);
uf.find(0) === uf.find(1);
Output
true
24. LRU Cache
class LRU<K, V> {
private map = new Map<K, V>();
constructor(private limit: number) {}
get(key: K): V | undefined {
if (!this.map.has(key)) return;
const val = this.map.get(key)!;
this.map.delete(key);
this.map.set(key, val);
return val;
}
set(key: K, value: V) {
if (this.map.has(key)) this.map.delete(key);
else if (this.map.size === this.limit) {
this.map.delete(this.map.keys().next().value);
}
this.map.set(key, value);
}
}
const cache = new LRU<number, string>(2);
cache.set(1, "A");
cache.set(2, "B");
cache.get(1);
cache.set(3, "C");
Output
Map { 1 => "A", 3 => "C" }
25. Async Queue (Concurrency Control)
class AsyncQueue {
private running = 0;
private queue: (() => Promise<void>)[] = [];
constructor(private limit: number) {}
async add(task: () => Promise<void>) {
if (this.running >= this.limit) {
await new Promise<void>(res => this.queue.push(res));
}
this.running++;
await task();
this.running--;
this.queue.shift()?.();
}
}
26. Memoization
function memoize<T extends (...args: any[]) => any>(fn: T): T {
const cache = new Map<string, any>();
return ((...args: any[]) => {
const key = JSON.stringify(args);
if (cache.has(key)) return cache.get(key);
const res = fn(...args);
cache.set(key, res);
return res;
}) as T;
}
27. Event Emitter
type Listener<T> = (data: T) => void;
class Emitter<T> {
private listeners: Listener<T>[] = [];
on(fn: Listener<T>) {
this.listeners.push(fn);
}
emit(data: T) {
this.listeners.forEach(fn => fn(data));
}
}
const emitter = new Emitter<number>();
emitter.on(v => console.log(v));
emitter.emit(10);
Output
10
28. Type-Safe Enum Pattern
const Status = {
Pending: "PENDING",
Active: "ACTIVE",
Closed: "CLOSED",
} as const;
type Status = typeof Status[keyof typeof Status];
29. Discriminated Union
type Action =
| { type: "ADD"; value: number }
| { type: "REMOVE"; id: number };
function reducer(action: Action) {
switch (action.type) {
case "ADD": return action.value;
case "REMOVE": return action.id;
}
}
30. Result / Either Pattern
type Result<T> =
| { ok: true; value: T }
| { ok: false; error: string };
function safeDivide(a: number, b: number): Result<number> {
return b === 0
? { ok: false, error: "divide by zero" }
: { ok: true, value: a / b };
}