Skip to main content

Exhaustive checking with empty type

flow.org/try

type Cases = 'A' | 'B';

function exhaust(x: Cases) {
if (x === 'A') {
// do stuff
} else if (x === 'B') {
// do different stuff
} else {
// only true if we handled all cases
(x: empty);
}
}

What happens when you add new case 'C'? You will get this error:

Cannot cast x to empty because string literal C [1] is incompatible with empty [2].

[1] 5 function exhaust(x: Cases) {
6 if (x === 'A') {
7 // do stuff
8 } else if (x === 'B') {
9 // do different stuff
10 } else {
11 // only true if we handled all cases
[2] 12 (x: empty);
13 }
14 }
15

You can be sure that you covered all the cases this way. Another real-life example:

export function exhaustB(reason: 'magicLink' | 'signUpConfirmation' | 'resetPassword') {
switch (reason) {
case 'magicLink':
return __('account.check_email_magic_link');
case 'signUpConfirmation':
return __('account.check_email_sign_up');
case 'resetPassword':
return __('account.you_will_recieve_password');
default:
return invariant(false, 'Unsupported reason: %j', (reason: empty));
}
}

Notice how is the empty type used at the same time with reason.