Seven tips, one for each day of the week. Each one replaces a helper you used to write, a library you used to install, or a bug you used to ship. All of them work in current Node, Bun and evergreen browsers.
Monday: .at(-1)
const steps = ["parse", "check", "emit"]; steps.at(-1); // "emit" steps.at(-2); // "check" No more arr[arr.length - 1]. Works on strings too.
Tuesday: toSorted doesn't mutate
const nums = [10, 1, 2]; const sorted = nums.toSorted((a, b) => a - b); // [1, 2, 10] nums; // still [10, 1, 2] sort sorts in place and returns the same array, which surprises everyone once. toSorted, toReversed and toSpliced return a copy. And always pass a compare function: [1, 2, 10].sort() is [1, 10, 2], because the default sort compares strings.
Wednesday: structuredClone for deep copies
const original = { when: new Date(), tags: new Set(["a"]), nested: { n: 1 } }; const copy = structuredClone(original); copy.nested.n = 2; original.nested.n; // 1 copy.when instanceof Date; // true Unlike JSON.parse(JSON.stringify(x)), it keeps Dates, Maps and Sets. It throws on functions, which is a feature: you find out.
Thursday: Object.groupBy
const people = [{ name: "Ada", team: "core" }, { name: "Alan", team: "web" }, { name: "Grace", team: "core" }]; Object.groupBy(people, (p) => p.team); // { core: [Ada, Grace], web: [Alan] } The reduce you've written a hundred times, built in. (More in #9.)
Friday: AbortSignal.timeout
await fetch("https://api.github.com/zen", { signal: AbortSignal.timeout(3000) }); fetch has no timeout of its own. This one line gives it one, and rejects with a TimeoutError. (More in #10.)
Saturday: Error with cause
try { JSON.parse("{oops"); } catch (err) { throw new Error("Could not read settings", { cause: err }); } Your message says what you were doing, and err.cause still has the original error. (More in #7.)
Sunday: satisfies
const routes = { home: "/", docs: "/docs", } satisfies Record<string, `/${string}`>; routes.docs; // fine, and autocomplete knows the keys // routes.blog; // error: Property 'blog' does not exist It checks that every value starts with /, without widening the object to Record<string, …>, so you keep the exact keys. (More in #6.)
Trying them
Each of these is a two-line experiment, which is what a scratchpad is for. In JSLab, a JavaScript & TypeScript scratchpad for macOS, Auto Log puts the value of each top-level expression beside its line as you type. In Tuesday's block, nums; shows up as ▸ Array(3); expand it to check it's still 10, 1, 2.
If a result surprises you, right-click it and choose Explain Result to ask Ask AI why. It works with your own key, or Ollama locally.
And if you'd like the tips about JSLab itself: in your first week, it shows a short tip in the status bar the first time you meet a feature, and Help → Learning & Tips has every feature with a video.
JSLab launches Nov 15. Learning & Tips: https://js-lab.app/docs/learn



