My Cheatsheets

JavaScript / TypeScript Notes

Spread Operator

What it is


Common Use

The spread operator is commonly used to append an item to an array in a way that creates a new array and doesn't modify the original one. This pattern is important for maintaining immutability in React state updates.

setTasks([...tasks, task]);

Explanation:

Result Example:

tasks = [1, 2, 3];
task = 4;
setTasks([...tasks, task]); // [1, 2, 3, 4]

Why It Matters (React Context)


Object Spreading

Spreading works on objects too; it copies key/value pairs from one object into a new one.

const user = { name: "Don", age: 65 };
const copy = { ...user }; // simple copy

Result:

// copy = { name: "Don", age: 65 }

This creates a shallow copy of user. The original object isn’t changed.

You can also modify data in the copy at the same time:

const updated = { ...user, name: "New Name" };

Result:

// updated = { name: "New Name", age: 65 }

Notes


Function Arguments

Spread can expand arrays into individual function arguments when a function expects separate parameters.

const numbers = [1, 2, 3];
const max = Math.max(...numbers); // equivalent to Math.max(1, 2, 3)

Why It’s Useful

Use in the Wild

Function-argument spreading is moderately common. It appears frequently with built-in utilities like Math.max(...numbers) and in wrapper functions that forward parameters (fn(...args)). You’ll see it often in utility code and React helpers, but less in core application logic.

Destructuring

What it is

Destructuring lets you unpack values from arrays or properties from objects directly into variables.
It’s a concise way to extract data without repeatedly referencing the parent structure.


Object Destructuring

Extracts specific properties from an object.

const user = { name: "Don", age: 65 };
const { name, age } = user;

Result:

// name = "Don"
// age = 65

This creates new variables name and age containing the values from user. The original object remains unchanged.

Common Uses


Array Destructuring

Extracts elements from arrays by position.

const colors = ["red", "green", "blue"];
const [first, second] = colors;

Result:

// first = "red"
// second = "green"

You can skip or collect remaining elements using the rest pattern:

const [first, ...rest] = ["red", "green", "blue"];
// first = "red"
// rest = ["green", "blue"]

Default Values

You can set defaults when the value might be missing.

const settings = { theme: "dark" };
const { theme = "light", layout = "grid" } = settings;
// theme = "dark"
// layout = "grid"

Variable Swapping (Array Trick)

Destructuring can also swap values without a temp variable.

let a = 1, b = 2;
[a, b] = [b, a];
// a = 2, b = 1

Why It Matters

Use in the Wild

Destructuring is very common in modern JavaScript and React. It’s elegant once you recognize the pattern, but can confuse readers unfamiliar with ES6 syntax. In React, you’ll see it constantly in function parameters, hook calls, and state handling.

Memory Management

How it works

Example

  1. setTasks([...tasks, task]); creates a new array.
  2. The variable tasks now points to the new array.
  3. The old array becomes unreferenced and eligible for garbage collection.

Key Notes


JavaScript & TypeScript Promises

What They Are

A Promise represents the eventual result of an asynchronous operation.

You can reframe it as:

A Promise guarantees a callback after the work completes with either a success or a failure result.

This replaces the uncertainty of callbacks with a consistent pattern you can chain and handle predictably.


States

State Meaning
Pending Waiting for completion
Fulfilled Completed successfully
Rejected Failed with an error

Before vs With Promises

// Callback style (no guarantees)
doSomething(function(result) { ... })

// Promise style (guaranteed callback)
doSomething()
  .then(result => { ... })
  .catch(error => { ... })

Creating a Promise

const myPromise = new Promise((resolve, reject) => {
  // async work
  if (ok) resolve(result)
  else reject(error)
})

Consuming a Promise

fetchData()
  .then(data => console.log(data))    // success
  .catch(err => console.error(err))   // failure
  .finally(() => console.log('done')) // always

Chaining

Each .then() returns a new Promise:

fetchUser()
  .then(u => fetchOrders(u.id))
  .then(o => process(o))
  .catch(e => handleError(e))

Async / Await (Modern Syntax)

async function getData() {
  try {
    const res = await fetch(url)
    return await res.json()
  } catch (e) {
    console.error(e)
  }
}

Same behavior, cleaner syntax.


Common Methods

Method Purpose
.then() Handle success
.catch() Handle failure
.finally() Always run
Promise.all() Wait for all to finish
Promise.any() First success
Promise.allSettled() Wait for all outcomes
Promise.resolve(x) Create resolved promise
Promise.reject(e) Create rejected promise

TypeScript Tip

const getUser = (): Promise<User> =>
  new Promise((resolve, reject) => { ... })

Async functions automatically return Promise<T>.


Key Points