Contents
Contents
Small habits compound. These are eight patterns I use daily to write code that's shorter, safer, and easier to read. Each one is a direct swap — no refactoring required.
Stop manually checking for null or undefined at every level.
Before
const city = user && user.address && user.address.city;After
const city = user?.address?.city;?. short-circuits and returns undefined the moment it hits a nullish value. Works on method calls too: user?.getProfile().
Use ?? instead of || when you only want to fall back on null or undefined — not on every falsy value.
Before
const count = input || 0; // breaks when input is 0After
const count = input ?? 0; // only falls back when input is null/undefined|| treats 0, "", and false as falsy and replaces them. ?? doesn't. This is the one that bites people the most.
When the variable name matches the key, you don't need to repeat yourself.
Before
const name = "Deni";
const role = "designer";
const user = { name: name, role: role };After
const user = { name, role };Works the same way in function return values and anywhere else you're constructing an object literal.
Pull values out of objects or arrays and set fallbacks in one line.
Before
function greet(options: { name?: string; greeting?: string }) {
const name = options.name ?? "stranger";
const greeting = options.greeting ?? "Hello";
return `${greeting}, ${name}`;
}After
function greet({ name = "stranger", greeting = "Hello" } = {}) {
return `${greeting}, ${name}`;
}The defaults live right at the parameter signature where they're easy to spot and change.
as const for Literal TypesWhen you define a config array or object, TypeScript widens the types by default. as const locks them to their literal values.
Before
const SIZES = ["sm", "md", "lg"]; // inferred as string[]
type Size = typeof SIZES[number]; // string — not what you wantAfter
const SIZES = ["sm", "md", "lg"] as const; // readonly ["sm", "md", "lg"]
type Size = typeof SIZES[number]; // "sm" | "md" | "lg" ✓Essential for deriving union types from constants. No more maintaining a separate type alongside an array.
as Assertionsas tells TypeScript to trust you. A type guard actually verifies it. Trust is earned.
Before
const value = JSON.parse(data) as User; // TS believes you, runtime doesn'tAfter
function isUser(value: unknown): value is User {
return (
typeof value === "object" &&
value !== null &&
"id" in value &&
"name" in value
);
}
const parsed = JSON.parse(data);
if (isUser(parsed)) {
// parsed is User here — and it's actually verified
}Use as only when you control both sides of the fence (e.g., casting a DOM element you queried yourself). For external data — API responses, JSON.parse, localStorage — write a guard.
Deeply nested conditionals are hard to follow. Return early and keep the happy path clean.
Before
function UserCard({ user }: { user: User | null }) {
if (user) {
if (user.isActive) {
return (
<div>
<h2>{user.name}</h2>
<p>{user.email}</p>
</div>
);
} else {
return <p>Account inactive.</p>;
}
} else {
return <p>No user found.</p>;
}
}After
function UserCard({ user }: { user: User | null }) {
if (!user) return <p>No user found.</p>;
if (!user.isActive) return <p>Account inactive.</p>;
return (
<div>
<h2>{user.name}</h2>
<p>{user.email}</p>
</div>
);
}Guard clauses at the top handle the edge cases. The main render at the bottom is clean and unindented.
Instead of typing any or duplicating a component for every data shape, use generics.
Before
function List({ items }: { items: any[] }) {
return (
<ul>
{items.map((item, i) => (
<li key={i}>{item.label}</li>
))}
</ul>
);
}After
function List<T extends { id: string; label: string }>({
items,
}: {
items: T[];
}) {
return (
<ul>
{items.map((item) => (
<li key={item.id}>{item.label}</li>
))}
</ul>
);
}TypeScript now knows the shape of each item. You get autocomplete, type errors on misuse, and the component works for any object that satisfies the constraint — no duplication required.
These eight patterns won't rewrite your codebase overnight, but they add up fast. Pick one, use it everywhere for a week, and it'll become reflex.