Skip to content
Advertisement

Why doesn’t Typescript infer return values correctly when possible return object types are specifically defined?

I’m trying to understand how Typescript infers the return values from a function call. Say I have a function called sendRequest that can return two specifically formatted objects. Why isn’t Typescript able to know that if loading is true, that the only possible value for data is null, and that if loading is false, the only possible value for data is a Data type? It is still saying that data could be null even though that’s impossible based on the possible return types listed.

type Data = { firstName: string; lastName: string };

type ReturnType =
  | { loading: true; data: null }
  | { loading: false; data: Data };

const sendRequest = (fetch: boolean): ReturnType => {
  if (fetch) {
    return { loading: true, data: null };
  }

  return { loading: false, data: { firstName: 'Bart', lastName: 'Simpson' } };
};

const { loading, data } = sendRequest(true);

if (loading) {
  data; // <-- Typescript says that `data` can be either `Data` or `null`, while based on the return type, and since `loading` if `true`, `data` can't be `null`.
}

Advertisement

Answer

This works as a discriminated union until you destructure the variables. TypeScript can understand that the data type of the union is conditional on the value of loading, but it doesn’t keep this information once you break it apart into two variables.

const ret = sendRequest(true);

if (!ret.loading) {
  ret.data; // <-- This is now of type Data, not null.
}

Playground Link

As jcalz points out in the comments, the behavior you’re requesting is tracked as microsoft/TypeScript#30581. (Thanks jcalz!)

User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement