Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

869 - DistributeUnions #6309

Open
okayu29 opened this issue Feb 7, 2022 · 4 comments
Open

869 - DistributeUnions #6309

okayu29 opened this issue Feb 7, 2022 · 4 comments
Labels
869 answer Share answers/solutions to a question en in English

Comments

@okayu29
Copy link

okayu29 commented Feb 7, 2022

type PopUnion<T> = UnionToIntersection<T extends any ? (x: T) => 1 : never> extends (x: infer U) => 1 ? U : never
type UnionToIntersection<T> = (T extends any ? (x: T) => 1 : never) extends (x: infer U) => infer R ?  U : never
type UnionToTuple<T, U = PopUnion<T>> = [T] extends [never] ? [] : [U, ...UnionToTuple<Exclude<T, U>>]

type Merge<T> = {[P in keyof T]: T[P]}

type DistributeObject<T, U = UnionToTuple<keyof T>>
    = U extends [infer L, ...infer R]
        ? DistributeUnions<T[keyof T & L]> extends infer V
            ? V extends any ? Merge<{[P in keyof T & L]: V} & DistributeObject<T, R>>: never
        : never
    : {}

type DistributeArray<T> 
    = T extends [infer L, ...infer R]
        ? DistributeUnions<L> extends infer U
            ? U extends any ? [U, ...DistributeArray<R>] : never
        : never
    : []

type DistributeUnions<T> 
    = T extends any
        ? T extends any[] ? DistributeArray<T>
        : T extends object ? DistributeObject<T>
        : T
    : never
@okayu29 okayu29 added answer Share answers/solutions to a question en in English labels Feb 7, 2022
@github-actions github-actions bot added the 869 label Feb 7, 2022
@dimitropoulos
Copy link
Contributor

This is a relatively concise explanation, and I like that it uses some previous challenges! I'll feature it on the video solutions!

@dimitropoulos
Copy link
Contributor

update: I spent some more time with this and I was able to remove UnionToIntersection and Merge, simplify DistributeUnions by removing one case, simplify DistributeArray by removing one case. I also was able to remove the intersections in DistributeObject.

That said, could you possibly explain why if you simply make this refactor

- type DistributeObject<T, U = UnionToTuple<keyof T>> =
+ type DistributeObject<T> =
-  U extends [unknown, ...infer R]
+ UnionToTuple<keyof T> extends [unknown, ...infer R]
  ? DistributeUnions<T[keyof T]> extends infer V
    ? V extends V
      ? { [P in keyof T]: V }
        & DistributeObject<T, R>
      : never
    : never
  : {};

it fails to work? Here's the full thing I have so far.

type PopUnion<T> =
  ((x: T) => unknown) extends
    (x: infer U) => unknown
  ? U
  : never;

type UnionToTuple<T, U = PopUnion<T>> =
  [T] extends [never]
  ? []
  : [U, ...UnionToTuple<Exclude<T, U>>];

type DistributeArray<T extends unknown[]> =
  T extends [infer Head, ...infer Tail]
  ? Head extends Head
    ? [Head, ...DistributeArray<Tail>]
    : never
  : [];

type DistributeObject<T, U = UnionToTuple<keyof T>> =
  U extends [unknown, ...infer R]
  ? DistributeUnions<T[keyof T]> extends infer V
    ? V extends V
      ? { [P in keyof T]: V }
        & DistributeObject<T, R>
      : never
    : never
  : {};

type DistributeUnions<T> =
  T extends unknown[]
    ? DistributeArray<T>
    : T extends object
      ? DistributeObject<T>
      : T

Any docs or PR description or anything you have on this would be much appreciated. I gather that when you put it in the generic constraints like that it has some distributive behavior or something that makes it different, but I'd really like a better understanding of what exactly is different.

@okayu29
Copy link
Author

okayu29 commented Jan 22, 2023

I am not very familiar with typescript and English, so maybe I don't really understand what you are saying.

However, your code passes the examples on the problem page, but not all the tests at https://tsch.js.org/869/play. Perhaps you are missing the page?

@dimitropoulos
Copy link
Contributor

dimitropoulos commented Jan 22, 2023

dang, I'm so sorry, yes, it turns out I was indeed missing some of the tests and I didn't know it. apologies!

Now that I have all the tests, you can still reduce a case in DistributeUnions:

type DistributeUnions<T> =
  T extends unknown[]
    ? DistributeArray<T>
    : T extends object
      ? DistributeObject<T>
      : T

otherwise, this is a quite robust solution!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
869 answer Share answers/solutions to a question en in English
Projects
None yet
Development

No branches or pull requests

2 participants