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.