Home > Mobile >  Typescript is changing type that was inferred
Typescript is changing type that was inferred

Time:07-22

I'm working on a complex generic and one of its parts is not working as expected:

// T and U are changed 
type Type<T> = T extends Array<infer U> ? U extends object ? Array<U> : T : never;

Inffered type U become UnionMember1[] | UnionMember2[] instead of expected (UnionMember1 | UnionMember2)[]:

type Z = { a: string };
type Y = { b: number }

const complex: Array<Z | Y> = [{ a: '1'}, { b: 1 }];

// Type '({ a: string; } | { b: number; })[]' is not assignable to type 'Z[] | Y[]'.
const complexChild: Type<typeof complex> = [{ a: '1'}, { b: 1 }]; 

Another curious part (but can be completely covered by fixing the case with inferred type) is that T has changed:

const primitive: Array<string | number> = ['1', 1];

// Type '(string | number)[]' is not assignable to type '(string[] & (string | number)[]) | (number[] & (string | number)[])'.
const primitiveChild: Type<typeof primitive> = ['1', 1];

Any suggstions how to fix that? Thanks!

Playground link

CodePudding user response:

The behaviour you are seeing here can be explained by the existence of distributive conditional types.

When you write U extends object ? ... : ... in the generic type Type and U resolves to a union, each member of the resulting union will be distributed individually to the next statement (in this case Array<U>).

You can stop the distibution by wrapping U and object inside a tuple.

type Type<T> = T extends Array<infer U> 
  ? [U] extends [object] 
    ? Array<U> 
    : T 
  : never;

Playground

  • Related