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!
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;