JS / TS

TypeScript Features I Actually Use Every Week (Not the Flashy Ones)

3 min read

TypeScript listicles love the exotic: recursive conditional types, mapped-type gymnastics, type-level parsers. Impressive, and almost none of it appears in my actual work. This is the opposite list — the features that earn a place in production code every week on a healthcare platform, chosen by usage frequency rather than impressiveness. Three deep-dives and one honest recap.

Template literal types

String types that follow a pattern. The everyday use isn't clever string manipulation — it's making "stringly-typed" APIs honest:

type PillarId = 'frameworks' | 'javascript' | 'css-ui';
type TagClass = `tag--${PillarId}`;
 
const cls: TagClass = 'tag--javascript'; // ✓
const bad: TagClass = 'tag--jvascript'; // ✗ compile error
 
// Or: event names that must follow a convention
type EntityEvent = `${'user' | 'order'}:${'created' | 'updated' | 'deleted'}`;
// 'user:created' | 'user:updated' | ... — all six, generated

Anywhere your codebase has naming conventions — CSS classes, event names, route paths, permission strings — template literal types turn the convention from a code-review comment into a compiler rule. Typos in these strings used to be runtime bugs; now they're red squiggles.

The satisfies operator

The fix for a dilemma that annoyed me for years. Annotate a config object and you get checking but lose inference precision; skip the annotation and you keep precision but lose checking:

type Config = Record<string, { url: string; timeout?: number }>;
 
// Old dilemma, option A: checked, but every value widens to the Config shape
const services: Config = {
  auth: { url: '/auth', timeout: 5000 },
};
// services.auth.timeout — fine, but TS forgot which keys exist
 
// satisfies: checked AND precisely inferred
const services2 = {
  auth: { url: '/auth', timeout: 5000 },
  billing: { url: '/billing' },
} satisfies Config;
 
services2.billing; // ✓ TS knows the exact keys
services2.auth.timeout.toFixed(0); // ✓ knows auth HAS timeout, billing doesn't

satisfies validates the value against the type without widening it. Every config object, theme definition, and route table I write now ends with a satisfies clause — it's the "have your cake and check it too" operator.

Const assertions

as const tells TypeScript to infer the narrowest possible type — literals instead of string, readonly tuples instead of arrays:

const STATUSES = ['draft', 'review', 'published'] as const;
// readonly ['draft', 'review', 'published'] — not string[]
 
type Status = (typeof STATUSES)[number];
// 'draft' | 'review' | 'published' — derived, not duplicated

That last line is the weekly workhorse: one runtime array, one derived type, zero drift. Add 'archived' to the array and the Status type, every exhaustive switch, and every validator using it update or error accordingly. Without as const, the array is string[] and the type must be maintained by hand alongside it — which is how the type and the runtime list end up disagreeing quietly. It's the same derive-don't-duplicate principle that makes discriminated unions work.

Utility types (the recap)

I've written a full post on these, so just the honest usage report: Pick/Omit weekly for shaping API payloads, Partial for every PATCH endpoint, Record for every lookup table, ReturnType whenever a function already knows a shape I'd otherwise duplicate. They're the standard library of the type system — unglamorous, constant.

The quick reference

FeatureWhat it's forWeekly use case
Template literal typesPattern-following stringsEvent names, CSS classes, routes
satisfiesCheck without wideningConfigs, themes, route tables
as constNarrowest inference, readonlyDerive union types from runtime arrays
Utility typesReshape existing typesAPI payloads, PATCH bodies, lookups

The connecting thread: every one of these is about making the code you already have the single source of truth — deriving types from values, validating without overwriting inference, turning conventions into contracts. That's the actual daily job of TypeScript. The flashy stuff is a hobby; this is the craft.

Found this useful?

Share

I post shorter takes on javascript & typescript and frontend leadership on LinkedIn — follow along there, or get in touch if you're working on something related.