TypeScript
Exhaustive switch cases
How to ensure you exhaust all possible cases in a switch:
ts
function getColorName(c: Color): string {
switch (c) {
case Color.Red:
return "red";
case Color.Green:
return "green";
// Forgot about Blue
default:
const exhaustiveCheck: never = c;
throw new Error(`Unhandled color case: ${exhaustiveCheck}`);
}
}- The
nevertype provides compile-time checking - The thrown
Errorprovides runtime checking
Credit: https://stackoverflow.com/a/58009992
Omit from a union type
If you try to Omit from a union type, you probably won't get what you expect. Consider this setup:
ts
interface A {
foo: string;
bar: string;
baz: string;
}
interface B {
foo: string;
fizz: number;
buzz: number;
}
type AorB = A | B;Then:
ts
type T1 = Omit<AorB, "foo">;
// equivalently:
// type T1 = {};Why? Let's look at the definition of Omit:
ts
type Omit<T, K extends string | number | symbol> = {
[P in Exclude<keyof T, K>]: T[P];
};The problem is that keyof AorB just becomes 'foo' (the intersection of the keys of A and B). So the mapped type only considers that key, and when you omit foo you are left with nothing.
Instead, we can use distributive conditional types to distribute the Omit over the union. The distributive version looks like this:
ts
type DistributiveOmit<T, K extends string | number | symbol> = T extends any ? Omit<T, K> : never;