piotrwitek / utility-types

Collection of utility types, complementing TypeScript built-in mapped types and aliases (think "lodash" for static types).
MIT License
5.54k stars 230 forks source link

Allow for a AllUnionKeys #192

Closed filipomar closed 9 months ago

filipomar commented 9 months ago

Is your feature request related to a real problem or use-case?

I have in my project a situation I simplified to:

enum FooEnum {
    ONE = 'ONE'
}

enum BarEnum {
    TWO = 'TWO'
}

type A = { x: FooEnum }
type B = { x: BarEnum, y: string }
type C = { z: number }

type AllKeys = keyof (A | B | C)

Where I want all the keys from my union, so 'x' | 'y' | 'z'

Now, currently that gives me a never, as the keys never match.

Describe a solution including usage in code example

In order to get those keys, I thought of trying to turn this Union into a Intersection by using:

import type { UnionToIntersection } from 'utility-types'

enum FooEnum {
    ONE = 'ONE'
}

enum BarEnum {
    TWO = 'TWO'
}

type A = { x: FooEnum }
type B = { x: BarEnum, y: string }
type C = { z: number }

type AllKeys = keyof UnionToIntersection<A | B | C>

But that also doesn't work, giving me string | number | symbol, as the intersection is also never.

But if I give them a common base type, across all of them, then it works, which came out as:

import type { UnionToIntersection } from 'utility-types'

enum FooEnum {
    ONE = 'ONE'
}

enum BarEnum {
    TWO = 'TWO'
}

type A = { x: FooEnum }
type B = { x: BarEnum, y: string }
type C = { z: number }

type AllUnionKeys<U> = keyof UnionToIntersection<Partial<U>>
type AllKeys = AllUnionKeys<A | B | C>

I tried to think about an alternative that feels less hacky, but came up short.

Who does this impact? Who is this for?

The impact is limited to anyone that opts to use it, and its for anyone that wants all the possible keys in an union.

I am willing to open a PR for this, but wanted first to see if the concept would be accepted.

piotrwitek commented 9 months ago

Hey @filipomar, thanks for your proposal and nicely filled feature request :) I like your idea and it works quite well :) so it would be great addition as it is quite common use case!

I imagine it like this:

name: UnionKeys<T>
desc: Get keys union of all objects in the union type `T`
credit: add yourself or the source please
add to the ## Object operators after OptionalKeys

tests: 1) add case from your example 2) add check of non union case

thank you :) Can't wait for your contribution!

filipomar commented 9 months ago

Alright, PR open at https://github.com/piotrwitek/utility-types/pull/193