typescripttypestuplestype-narrowing

Control flow not type-narrowing with union tuple?


I have an issue with tuples:

export async function redirectIf(
  nextCookies: NextApiRequestCookies,
  options: { notAuth: PagePath },
): Promise<[Redirect, undefined] | [undefined, UserDto]>;

It is not aware that the user exists if redirect does not:

VSCode view of the type

Playground


Solution

  • Latest Answer

    This has been fixed since TypeScript v4.6, see Control Flow Analysis for Destructured Discriminated Unions.

    Old Answer

    Thanks to Gerrit0#7591 on the TypeScript Community discord server who answered:


    TypeScript does not track narrowing across separate variables. If you have:

    const x: [true, string] | [false, Error] = ...
    

    And check the first element of the tuple, then TS can narrow down the type:

    if (x[0]) {
      // TS knows x[1] is a string
    }
    

    But if you destructure first, then you have two (as far as TS knows) totally unrelated variables.

    const [isStr, val] = x
    if (isStr) {
       // val is string | Error, not string
    }
    

    There's no real workaround to this besides not destructuring, or doing destructuring after having narrowed the type sufficiently.

    if (x[0]) {
      const val = x[1] // val: string
    }