The TypeScript satisfies Operator: Checking Types Without Losing Detail
A type annotation checks a value against a type, but then the variable becomes that type, and you lose the specific details. satisfies checks the value without changing its inferred type.
The problem with annotations
type Route = { path: string; auth: boolean };
const routes: Record<string, Route> = {
home: { path: '/', auth: false },
dashboard: { path: '/dashboard', auth: true },
};
routes.dashbaord; // no error for the typo: any string key is allowed
With satisfies
const routes = {
home: { path: '/', auth: false },
dashboard: { path: '/dashboard', auth: true },
} satisfies Record<string, Route>;
routes.dashbaord; // Error: property 'dashbaord' does not exist
routes.dashboard.path; // autocompletes, and the value is still checked against Route
Mistakes inside the object, such as a missing auth field, are still reported.
as const satisfies
Combine both to get literal types that are also validated:
const STATUS_COLORS = {
active: 'green',
suspended: 'orange',
deleted: 'red',
} as const satisfies Record<Status, string>;
type Color = (typeof STATUS_COLORS)[keyof typeof STATUS_COLORS]; // 'green' | 'orange' | 'red'
If someone adds a new Status, this object fails to compile until a colour is added.
Great uses
- Configuration objects (routes, feature flags, theme tokens).
- Lookup tables keyed by a union type.
- Default exports of config files:
export default { ... } satisfies Config.
When to still use an annotation
Use a plain annotation when you want the wider type, for example a variable that will be reassigned later with other valid values.
Was this article helpful?
Comments
No comments yet. Have a question or a tip? Be the first to share it.