Typescript can't infer inner type of Iterable of Iterable

Viewed 83

Here is a simple function that takes in an Iterable of Iterables.

function unwrapFirst<T extends Iterable<U>, U>(iter: Iterable<T>): U {
  return [...[...iter][0]][0];
}

unwrapFirst([[1,2,3],[4,5,6]]);

I expected TypeScript to infer the type of U correctly as number but it infers it as unknown. Can someone explain why? And how to get TypeScript to correctly infer U?

1 Answers

Generic constraints are not used as inference sites. See microsoft/TypeScript#44711 for a similar issue.

You were presumably expecting the compiler to infer U from T given that T is constrained to Iterable<U>. But that does not happen because constraints are not used as inference sites. So the type inferred for T has no effect on U, and therefore U fails to be inferred and the compiler falls back to unknown.

If you want to use inference to get U from T, you will make the function generic in only T, and then calculate U via conditional type inference. For example:

function unwrapFirst<T extends Iterable<any>>(
    iter: Iterable<T>
): T extends Iterable<infer U> ? U : never {
    return [...[...iter][0]][0];
}

const res = unwrapFirst([[1, 2, 3], [4, 5, 6]]);
// const res: number

Looks good!

Playground link to code

Related