Type Narrowing
How TypeScript refines types through control flow — predicates, discriminants, and patterns that keep strict mode honest.
intermediate2 min read
- typescript
- narrowing
- types
Strict TypeScript is only useful if you narrow unions instead of asserting them away. Narrowing is how control flow becomes type safety.
Built-in guards
function len(x: string | string[]) {
if (typeof x === 'string') return x.length;
return x.length; // string[]
}
function process(x: string | null) {
if (x == null) return;
// x is string
console.log(x.toUpperCase());
}
typeof, instanceof, equality checks, and in all narrow.
Discriminated unions
Model state machines explicitly:
type RequestState<T> =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'success'; data: T }
| { status: 'error'; error: Error };
function view(state: RequestState<User>) {
switch (state.status) {
case 'idle':
return 'Start';
case 'loading':
return '…';
case 'success':
return state.data.name;
case 'error':
return state.error.message;
}
}
The discriminant (status) is the key. Avoid optional fields like data?: T; error?: Error for mutually exclusive states.
User-defined type predicates
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined;
}
const pets: (Fish | Bird)[] = [];
pets.filter(isFish).forEach((f) => f.swim());
Prefer genuine runtime checks over as casts.
Assertion functions
function assertDefined<T>(x: T | null | undefined, msg: string): asserts x is T {
if (x == null) throw new Error(msg);
}
After assertDefined(user), TypeScript treats user as defined.
What not to do
// Escaping the type system — last resort only
const el = document.querySelector('.app') as HTMLDivElement;
Prefer:
const el = document.querySelector('.app');
if (!(el instanceof HTMLDivElement)) throw new Error('missing .app');
Interview takeaway
Explain narrowing as control-flow analysis. Show a discriminated union for async UI state. Mention predicates when filters must preserve types.
Related guides
- unknown vs anyunknown vs any explained for frontend engineers — mental model, examples, common mistakes, and interview tips.
- Type Assertions SafelyType Assertions Safely explained for frontend engineers — mental model, examples, common mistakes, and interview tips.
- Non-null Assertion OperatorNon-null Assertion Operator explained for frontend engineers — mental model, examples, common mistakes, and interview tips.
- Typing React PropsTyping React Props explained for frontend engineers — mental model, examples, common mistakes, and interview tips.
- Typing React EventsTyping React Events explained for frontend engineers — mental model, examples, common mistakes, and interview tips.