When to use
- Validating object shape while preserving literal types.
- Defining config objects, route maps, locale maps, or handler maps.
- Choosing between
: Type,satisfies Type,as const, andas Type. - Fixing widened types caused by annotations.
Goal
Validate that a value matches a type without replacing the value's inferred type.
Rules
- Use
satisfieswhen value specificity should win. - Use
: Typewhen the variable should have the wider type. - Use
as const satisfiesfor readonly literal config. - Avoid
as Typeunless it is a deliberate escape hatch. - Use
Record<Union, Value>withsatisfiesfor exhaustive maps.
Mental Model
: Type: type wins, value may widen.satisfies Type: value wins, shape is checked.as Type: tells TypeScript to trust you.- no annotation: inference only.
Pattern
type Locale = "en" | "cs";
const localeIds = {
en: "1",
cs: "2",
} as const satisfies Record<Locale, string>;
Object Validation
type Colors = "red" | "green" | "blue";
type RGB = [number, number, number];
const palette = {
red: [255, 0, 0],
green: "#00ff00",
blue: [0, 0, 255],
} satisfies Record<Colors, string | RGB>;
palette.green.toUpperCase();
Use Cases
- Route maps.
- Locale maps.
- Feature flag config.
- Status labels.
- Event handler maps.
- Design token objects.
Avoid
- Annotating config objects so all literals widen.
- Using
satisfieswhen later reassignment needs wider type. - Using
as constafter a type annotation and expecting literals to survive.
Output
- Whether to use annotation,
satisfies,as const satisfies, or inference. - Reason tied to widening or validation.
- Example replacement when useful.