Glossary / Type narrowing
Type narrowing
Type narrowing is TypeScript's control-flow analysis that refines a broad type to a more specific type after guards and assignments. It allows safe use of union members while preserving runtime JavaScript checks as the source of evidence.
Narrowing mechanisms
Common guards include typeof, equality checks, in, instanceof, discriminant comparisons, truthiness, and user-defined type predicates. Array.isArray narrows arrays; assertion functions can tell the checker that a condition must hold or throw. Control-flow analysis tracks branches, returns, and assignments, but may widen when values are mutated or captured.
function format(value: string | number) {
if (typeof value === 'string') return value.toUpperCase();
return value.toFixed(2);
}
Optional chaining is not a general type guard for unrelated values; non-null assertions (!) bypass checking rather than proving safety. A predicate such as value is User is trusted by the compiler, so an incorrect implementation creates unsoundness. Prefer checking each required field and handling arrays, null, and malformed input.
Runtime boundaries
Values from JSON, network, storage, and JavaScript callers are not made trustworthy by TypeScript annotations. Use unknown at boundaries and narrow with actual runtime conditions or a schema validator. Keep validation and type guards aligned as the schema evolves.
Interview questions
- What is narrowing? Refining a union or broad type based on runtime control-flow evidence.
- Does
value!validate a value? No; it suppresses a nullability diagnostic. - Can custom predicates be wrong? Yes; TypeScript trusts the declared predicate.
- Why start external values as
unknown? It requires checking before use, unlikeany. - What are common narrowing guards?
typeof,instanceof,in, equality/discriminants, and validated predicates.