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. }
As jcalz points out in the comments, the behavior you’re requesting is tracked as microsoft/TypeScript#30581. (Thanks jcalz!)