Look-up a key in an object with exhaustiveness check with TypeScript

Viewed 165

Say my server responds with the following: 'a', 'b', or 'c'. These map to 'alpha', 'beta' or 'gamma' in my app. If I were using JS, I'd do the following to translate:

const mapping = {
  a: 'alpha',
  b: 'beta',
  c: 'gamma'
}

const lookUp = serverResponse => mapping[serverResponse];

I can do the equivalent in TypeScript. However, let's say I also want the guarantee that in case the server adds 'd' for 'delta', I can modify one location in my code and let TS help me with its type system to guide the rest of my refactoring.

type ServerResponse = 'a' | 'b' | 'c';
type ActualMeaning = 'alpha' | 'beta' | 'gamma';

const mapping: { [key in ServerResponse]: ActualMeaning } = {
  a: 'alpha',
  b: 'beta',
  c: 'gamma'
} as const;

const shouldNeverReachHere = (x: never): never => {
  throw new Error(`This value not exhaustively handled: ${x}`);
}

const lookup = (serverResponse: ServerResponse): ActualMeaning => {
  if (serverResponse in mapping) return mapping[serverResponse];
  return shouldNeverReachHere(serverResponse);
}

I'd expect that since the mapping is known at compile time (because of the as const), the exhaustiveness check for shouldNeverReachHere(serverResponse) would have worked. However, I get the following error for that line:

Argument of type '"a" | "b" | "c" is not assignable to parameter of type 'never'.
  Type '"a"' is not assignable to type 'never'. ts(2345)

If I change the function to use a switch instead of looking up in an object, it works. But switch statements are clunky. I also want to convert both ways, which makes objects very easy to work with, as opposed to a switch.

Any idea how I could make the above code work in TypeScript?

1 Answers

Not sure about exhaustiveness check, but in this case ServerResponse is incompatible with never.

Try this definition of your abort function:

const shouldNeverReachHere = (x: unknown): never => {
    throw new Error(`This value not exhaustively handled: ${x}`);
}

Playground

Related