This note answers a practical question: when working with objects, arrays, dictionaries, and loops, which syntax should you use and why?
?? vs ||
?? uses the fallback only when the value is null or undefined.
const value = input ?? "default";|| uses the fallback for any falsy value, including false, 0, "", NaN, null, and undefined.
const page = query.page || 1;If 0 is a valid value, avoid ||.
const discount = userDiscount ?? 0;Record Dictionaries
Record<K, V> describes a key-value map.
const userAges: Record<string, number> = {
Alice: 25,
Bob: 30,
};If keys are a fixed set, use a union type.
type Role = "admin" | "editor" | "viewer";
const permissions: Record<Role, string[]> = {
admin: ["read", "write", "delete"],
editor: ["read", "write"],
viewer: ["read"],
};This is safer than Record<string, string[]> because missing roles become compile errors.
Index Signatures
Index signatures are useful when keys are fully dynamic.
interface ScoreMap {
[name: string]: number;
}
const scores: ScoreMap = {};
scores.Alice = 95;The tradeoff is that any string key is allowed.
Choosing a Loop
Use for when you need an index, early exit, or precise loop control.
for (let i = 0; i < items.length; i++) {
if (items[i] === target) break;
}Use for...of when you want values from arrays, strings, Sets, or other iterables.
for (const fruit of fruits) {
console.log(fruit);
}Use for...in for object keys, but guard against inherited properties.
for (const key in person) {
if (Object.prototype.hasOwnProperty.call(person, key)) {
console.log(key, person[key as keyof typeof person]);
}
}forEach vs map
forEach is for side effects and does not return a new array.
numbers.forEach((num) => {
console.log(num);
});map transforms an array and returns a new one.
const doubled = numbers.map((num) => num * 2);Simple rules:
- Need a new array:
map - Need filtering:
filter - Need accumulation:
reduce - Logging or side effects:
forEach - Need
breakorcontinue:for...oforfor