type-challenges / type-challenges

Collection of TypeScript type challenges with online judge

Home Page:https://tsch.js.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Distributive Conditional Types & Mapped Types does not work together

jiamingparker opened this issue · comments

For challenge 20, the most rated solution does not work for test case 4 for me:

declare function PromiseAll<T extends any[]>(values: readonly [...T]): Promise<{ [K in keyof T]: T[K] extends Promise<infer R> ? R : T[K] }>;

I have to move the extends part to another generic type

type MyAwaited<T> = T extends Promise<infer R> ? R : T
declare function PromiseAll<T extends any[]>(values: readonly [...T]): Promise<{ [K in keyof T]: MyAwaited<T[K]> }>;

This is really confusing. My explanation is distributive conditional types does not work in mapped types. When T[K] is a union type number | Promise<number>, the distributive behavior does not happen. But if we use another generic type, the context is clear and the distributive behavior happen again.

Anybody can explain on this?

For the first case:

declare function PromiseAll<T extends any[]>(values: readonly [...T]): Promise<{ [K in keyof T]: T[K] extends Promise<infer R> ? R : T[K] }>;

It equals to:

// replace T[K] to number | Promise<number>
type Value = number | Promise<number> extends Promise<infer R> ? R : number | Promise<number>;

It obviously will return number | Promise<number>.

But in the second case, you abstract the judge Statement, so it will be:

type MyAwaited<T> = T extends Promise<infer R> ? R : T;
type Value = MyAwaited<number | Promise<number>> = MyAwaited<number> |  MyAwaited<Promise<number>> = number;

So it works fine.