JavaScript & TypeScript Cheat Sheet
Modern JavaScript (up to ES2025) for browsers and Node.js, then TypeScript (5.x to 7.0) on top: types, generics, narrowing and project setup. Tags like (ES2022) show when a feature arrived; everything here runs in current browsers and Node 22+.
On this page
Variables, Types & Operators #
| Code | What it does |
|---|---|
const max = 10 | Constant binding: use by default (objects stay mutable) |
let count = 0 | Variable you can reassign; block-scoped like const |
var x | Old function-scoped variable: don't use in new code |
typeof x | "string", "number", "boolean", "undefined", "object", "function", "bigint", "symbol" |
typeof null | "object" (historic bug): test with x === null |
Array.isArray(x) | The reliable way to detect an array |
a === b / a !== b | Strict equality without type conversion (avoid ==) |
user?.address?.city | Optional chaining: undefined instead of a crash (ES2020) |
obj.method?.() | Call only if the method exists |
a ?? b | b only when a is null or undefined (ES2020) |
a || b | b when a is falsy: 0, "", false, null, undefined, NaN |
x ??= 5 / x ||= 5 / x &&= f(x) | Logical assignment (ES2021) |
cond ? a : b | Ternary: inline if/else |
2 ** 10 | Exponent: 1024 |
Strings & Numbers #
| Code | What it does |
|---|---|
`Hi ${name}!` | Template literal: insert values, may span lines |
s.includes("x") / s.startsWith("x") / s.endsWith("x") | Contains / begins with / ends with |
s.slice(1, 4) / s.slice(-3) | Substring (negative counts from the end) |
s.split(",") / arr.join(", ") | String to array and back |
s.trim() / s.toUpperCase() / s.toLowerCase() | Strip whitespace / change case |
s.replaceAll("a", "b") | Replace every match (ES2021); replace does only the first |
s.padStart(3, "0") | "7" becomes "007" |
Number("42") / parseInt("42px", 10) | Convert: Number("42px") is NaN, parseInt gives 42 |
Number.isNaN(x) / Number.isInteger(x) | Reliable number checks |
n.toFixed(2) | 3.14159 becomes the string "3.14" |
0.1 + 0.2 | 0.30000000000000004: floats are imprecise, store money in cents |
Math.round(x) / Math.floor(x) / Math.ceil(x) | Round / down / up |
Math.max(...nums) | Largest value of an array (spread it into arguments) |
Math.floor(Math.random() * 6) + 1 | Random integer from 1 to 6 |
1_000_000 / 123n | Numeric separator (ES2021) / BigInt for huge integers |
n.toLocaleString("nl-BE") | 1234.5 becomes "1.234,5" |
Arrays #
| Code | What it does |
|---|---|
a.push(x) / a.pop() | Add / remove at the end (unshift / shift at the start) |
a.map(x => x * 2) | New array with every item transformed |
a.filter(x => x > 1) | New array with the items that pass |
a.reduce((sum, x) => sum + x, 0) | Combine into one value (always give a start value) |
a.find(fn) / a.findIndex(fn) | First match / its index (undefined / -1 if none); findLast (ES2023) |
a.some(fn) / a.every(fn) | At least one / all items pass |
a.includes(2) / a.indexOf(2) | Contains the value / its position or -1 |
a.at(-1) | Last item (ES2022), also works on strings |
a.slice(1, 3) / a.splice(i, 1) | Copy a part / remove 1 item at index i (mutates) |
a.flat() / a.flatMap(fn) | Flatten one level / map then flatten (ES2019) |
a.toSorted((x, y) => x - y) | Sorted copy, numbers ascending (ES2023); sort mutates |
a.toReversed() / a.with(0, "x") | Reversed copy / copy with one item replaced (ES2023) |
[...a, ...b] | Copy or merge arrays |
const [first, , third, ...rest] = a | Destructuring (skip items with commas) |
Array.from({ length: 3 }, (_, i) => i) | Build an array: [0, 1, 2] |
Object.groupBy(a, x => x.type) | Group into an object of arrays (ES2024) |
Objects #
| Code | What it does |
|---|---|
const user = { name, age } | Shorthand for { name: name, age: age } |
{ [key]: value } | Computed property name |
const { name, role = "user" } = user | Destructure with a default value |
const { name: userName } = user | Destructure and rename |
const { password, ...safe } = user | Rest: everything except password |
{ ...defaults, ...options } | Shallow merge (later keys win) |
Object.keys(o) / Object.values(o) / Object.entries(o) | Keys / values / [key, value] pairs |
Object.fromEntries(pairs) | Pairs back to an object (ES2019) |
Object.hasOwn(o, "key") / "key" in o | Own property (ES2022) / own or inherited |
structuredClone(o) | Deep copy, including Dates, Maps and Sets (not functions) |
Object.freeze(o) | Make read-only (shallow) |
Control Flow & Functions #
| Code | What it does |
|---|---|
if (a) {} else if (b) {} else {} | Conditions |
switch (v) { case 1: ...; break; default: ... } | One value against many cases (don't forget break) |
for (const item of items) | Loop over values (arrays, strings, Maps, Sets) |
for (const [i, item] of items.entries()) | Values with their index |
for (const key in obj) | Loop over object keys (not for arrays) |
for (let i = 0; i < n; i++) / while (cond) {} | Counting loop / loop while true |
break / continue | Leave the loop / skip to the next round |
function add(a, b) { return a + b; } | Declaration (hoisted: usable before its line) |
const add = (a, b) => a + b | Arrow function with implicit return (no own this) |
const make = () => ({ id: 1 }) | Arrow returning an object: wrap it in () |
function greet(name = "guest") | Default parameter |
function sum(...nums) | Rest parameter: all arguments as an array |
function draw({ x, y }) | Destructure an object parameter |
const counter = () => { let n = 0; return () => ++n; } | Closure: the inner function keeps its own private n |
Classes & Modules #
class Animal {
static count = 0; // static field (ES2022)
#secret = "hidden"; // truly private field (ES2022)
sound = "..."; // public field
constructor(name) { this.name = name; Animal.count++; }
speak() { return `${this.name} says ${this.sound}`; }
get secretLength() { return this.#secret.length; }
}
class Dog extends Animal {
sound = "woof";
speak() { return super.speak() + "!"; }
}
new Dog("Rex").speak(); // "Rex says woof!"
| Code | What it does |
|---|---|
export const PI = 3.14 | Named export (as many as you like) |
export default function App() {} | Default export (one per file) |
import { PI, area } from "./math.js" | Named import: names must match, keep the .js |
import App from "./App.js" | Default import: pick any name |
import { PI as pi } from "./math.js" | Rename on import |
import * as math from "./math.js" | Everything as one object |
const { chart } = await import("./chart.js") | Dynamic import: load code on demand |
"type": "module" | In package.json: .js files in Node are ES modules |
Promises, Async & Errors #
async function getUser(id) {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`); // 404/500 don't reject!
return res.json();
}
try {
const user = await getUser(1);
} catch (err) {
console.error("Failed:", err.message);
} finally {
spinner.hidden = true; // runs either way
}
| Code | What it does |
|---|---|
await p | Wait inside an async function, or at the top level of a module (ES2022) |
Promise.all([p1, p2]) | Run in parallel; rejects as soon as one fails |
Promise.allSettled([p1, p2]) | Wait for all: { status, value } or { status, reason } each (ES2020) |
Promise.any([p1, p2]) | First success; rejects only if all fail (ES2021) |
Promise.race([p1, p2]) | First to finish, success or failure |
new Promise((resolve, reject) => {}) | Wrap callback-style code |
const sleep = ms => new Promise(r => setTimeout(r, ms)) | Delay helper: await sleep(500) |
fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) }) | Send JSON |
fetch(url, { signal: AbortSignal.timeout(5000) }) | Give up after 5 seconds |
throw new Error("Save failed", { cause: err }) | Wrap an error, keep the original (ES2022) |
err instanceof TypeError | Check the error type in catch |
Map, Set, JSON & Dates #
| Code | What it does |
|---|---|
const m = new Map() | Key-value store: any key type, keeps insertion order |
m.set(k, v) / m.get(k) / m.has(k) / m.delete(k) | Basic Map operations (m.size = count) |
const s = new Set([1, 2, 2]) | Unique values: {1, 2} (add, has, delete, size) |
[...new Set(arr)] | Remove duplicates from an array |
a.union(b) / a.intersection(b) / a.difference(b) | Set math, returns a new Set (ES2025) |
JSON.stringify(obj, null, 2) | To a JSON string, pretty-printed with 2 spaces |
JSON.parse(text) | JSON string to value (throws on invalid JSON) |
new Date() / Date.now() | Now, as a Date / in milliseconds since 1970 |
new Date("2026-10-11T09:30:00") | Parse ISO text (no Z at the end = local time) |
d.getFullYear() / d.getMonth() / d.getDate() | Year / month (0 = January) / day of month |
d.toISOString() | Always UTC: 09:30 in Brussels gives "2026-10-11T07:30:00.000Z" |
d.toLocaleDateString("nl-BE") | Local format: "11/10/2026" |
DOM Basics #
| Code | What it does |
|---|---|
document.querySelector(".card") | First element matching a CSS selector (or null) |
document.querySelectorAll("li") | All matches as a NodeList (works with for...of) |
el.addEventListener("click", e => {}) | Run code on an event |
e.preventDefault() / e.target | Stop default behaviour (form submit) / element that fired |
el.classList.add("on") / .remove("on") / .toggle("on") | Manage CSS classes (.contains to test) |
el.dataset.userId | Reads the data-user-id attribute |
el.textContent = text | Set text safely: HTML is not parsed |
el.innerHTML = html | Parse HTML: never with user input (XSS risk) |
document.createElement("li") | Create a new element |
parent.append(child) / el.remove() | Insert / remove an element |
input.value | Current value of a form field (always a string) |
TypeScript Basics #
| Code | What it does |
|---|---|
let title: string = "Hi" | Type annotation |
let count = 0 | Inferred as number: annotate only where inference can't help |
number[] / Array<number> | Array of numbers |
[string, number] | Tuple: fixed length and types |
function add(a: number, b: number): number | Parameter and return types |
(x: number) => string | Function type |
string | number | Union: one of these types |
A & B | Intersection: has everything from both |
"sm" | "md" | "lg" | Literal types: only these exact values |
email?: string / readonly id: number | Optional / cannot be reassigned |
unknown / any | Must narrow before use (safe) / switches checking off (avoid) |
void / never | Returns nothing / never returns (always throws) |
value as User / value! | Assertion / "not null": no runtime check, use sparingly |
interface User { // object shapes; can extend and be merged
readonly id: number;
name: string;
email?: string;
}
interface Admin extends User { role: "admin" }
type ID = string | number; // type alias: also unions, tuples, primitives
type Point3D = { x: number; y: number } & { z: number };
Generics & Utility Types #
function first<T>(items: T[]): T | undefined { return items[0]; }
first([1, 2]); // T is inferred as number
interface ApiResponse<T> { data: T; error?: string }
function longest<T extends { length: number }>(a: T, b: T): T {
return a.length >= b.length ? a : b;
}
| Code | What it does |
|---|---|
Partial<User> / Required<User> | All properties optional / required |
Readonly<User> | All properties read-only |
Pick<User, "id" | "name"> | Only these keys |
Omit<User, "email"> | Everything except these keys |
Record<string, number> | Object with these key and value types |
ReturnType<typeof fn> / Parameters<typeof fn> | Return type / parameter types (tuple) of a function |
Awaited<Promise<User>> | The resolved type: User |
NonNullable<T> | Removes null and undefined |
Exclude<T, U> / Extract<T, U> | Remove / keep union members |
keyof User | Union of the keys: "id" | "name" | "email" |
typeof config / User["name"] | Type of a value / type of one property |
Narrowing & Type Tricks #
| Code | What it does |
|---|---|
typeof x === "string" | Narrow primitives |
"swim" in pet | Narrow by property |
err instanceof Error | Narrow class instances (e.g. in catch) |
x != null | Removes both null and undefined |
function isUser(x: unknown): x is User | Custom type guard |
as const | Readonly, exact literal types |
satisfies Type | Check against a type but keep the precise inferred type (TS 4.9+) |
enum Role { Admin, User } | Enum: emits runtime code, Node's type stripping can't run it |
type Role = "admin" | "user" | Union of literals: usually preferred over enums |
type Shape = { kind: "circle"; radius: number } | { kind: "rect"; w: number; h: number };
function area(s: Shape): number {
switch (s.kind) { // discriminated union: TS narrows per case
case "circle": return Math.PI * s.radius ** 2;
case "rect": return s.w * s.h;
default: { const missing: never = s; return missing; } // error if a case is missing
}
}
const ROLES = ["admin", "editor"] as const;
type Role = (typeof ROLES)[number]; // "admin" | "editor"
const config = { port: 3000 } satisfies Record<string, string | number>;
config.port.toFixed(); // still number, not string | number
TypeScript Setup & Running #
| Code | What it does |
|---|---|
npm i -D typescript | Install the compiler in the project |
npx tsc --init | Create a tsconfig.json with good defaults |
npx tsc / npx tsc --noEmit | Compile to JS / only type-check (--watch to repeat on save) |
"strict": true | All strict checks incl. null checks (default since TS 6.0, older projects must set it) |
"target": "ES2022" | JavaScript version to output |
"module": "NodeNext" | Node's module rules; with Vite and other bundlers use "ESNext" + "moduleResolution": "bundler" |
"noUncheckedIndexedAccess": true | arr[i] becomes T | undefined |
"erasableSyntaxOnly": true | Forbid enums, namespaces etc. so Node can strip types (TS 5.8+) |
node app.ts | Run TS directly: Node strips types without checking them (Node 22.18+ / 23.6+) |
node --experimental-strip-types app.ts | Same on older Node 22 versions |
npx tsx app.ts | Run any TS, including enums (tsx watch restarts on save) |
import type { User } from "./types.ts" | Type-only import, removed at runtime |
Tips #
- Default to
constand===; reach forletonly when you reassign. [10, 9, 1].sort()gives[1, 10, 9]because it compares strings: pass(a, b) => a - bfor numbers.forEachdoesn't wait forawait: usefor...ofto go one by one, orawait Promise.all(items.map(fn))for parallel.fetchonly rejects on network errors: always checkres.okbefore reading the body.- Types vanish at runtime: validate API responses and
JSON.parseresults (for example with Zod) instead of trustingas. - Prefer
unknownoverany. Since TS 6,tsc file.tsstops with an error when atsconfig.jsonis present: run plainnpx tsc(or add--ignoreConfig).
Nothing on this sheet matches “”.