In TypeScript, pattern matching is implemented through "discriminated unions". Each object in the union is assigned a mandatory discriminator field (usually a string, for example type), which TypeScript uses to distinguish the variants.
Example:
type Success = { type: 'success'; data: string }; type Failure = { type: 'failure'; error: string }; type Result = Success | Failure; function handleResult(result: Result) { switch (result.type) { case 'success': // result: Success console.log(result.data); break; case 'failure': // result: Failure console.error(result.error); break; } }
In the switch/case or if statement on the discriminator field, TypeScript will narrow the type down to the specific variant.
Main advantages:
If a new variant is added to the discriminated union, will TypeScript strictly require updating all switch-case statements to handle the new variant?
Answer: No, only if you explicitly add handling for the "impossible" variant. For example, by using the never function:
Example:
function assertNever(x: never): never { throw new Error('Unexpected variant: ' + x); } function handle(r: Result) { switch(r.type) { case 'success': /* ... */; break; case 'failure': /* ... */; break; default: return assertNever(r); // TS will throw an error if a new type appears } }
Story
After expanding the "Result" type with a new variant ('pending'), in several places in the application, old switch-case statements did not handle this case. As a result, some interfaces stopped working. The error was noticed only in production a week after the release.
Story
Attempting to use a discriminated union without a unique discriminator (the type field duplicated in two types) led to "blurring" of types: TypeScript stopped narrowing the type precisely, allowing access to non-existent fields without a compilation error. Several critical bugs reached production.
Story
In the project, pattern matching was implemented using if-else statements across several fields instead of using a single explicit discriminator. This complicated the transition to exhaustiveness checking using the never function and made the code less readable — the switch-case statements worked incorrectly, and new variants "broke" existing logic.