Control flow not type-narrowing with union tuple?

Viewed 97

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

1 Answers

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
}

Related