Skip to content

Instantly share code, notes, and snippets.

@tmatz
Last active January 24, 2024 07:53
Show Gist options
  • Save tmatz/bdbdaf70ceeaa80503e0174f7233a1db to your computer and use it in GitHub Desktop.
Save tmatz/bdbdaf70ceeaa80503e0174f7233a1db to your computer and use it in GitHub Desktop.
toMergedUnion for deconstructing a discriminated union
type UnionAllKeys<U> = U extends infer T ? keyof T : never
type UnionCommonKeys<U> = keyof U
type UnionPartialKeys<U> = Exclude<UnionAllKeys<U>, UnionCommonKeys<U>>
type UnionPartialProperty<U, Key extends string> =
U extends infer T
? Key extends keyof T
? T[Key]
: never
: never
export type MergedUnion<
U extends any,
CommonKey extends keyof U = UnionCommonKeys<U>,
PartialKey extends string = UnionPartialKeys<U>
> =
U extends undefined | null
? U
: { [K in CommonKey]: U[K] }
& { [K in PartialKey]?: UnionPartialProperty<U, K> }
export const toMergedUnion = <T extends any>(value: T) =>
value as MergedUnion<T>
/* _____________ Test Cases _____________ */
import { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<UnionAllKeys<A | B>, 'type'|'a'|'b'>>,
Expect<Equal<UnionPartialKeys<A | B>, 'a'|'b'>>,
Expect<Equal<UnionPartialProperty<A, 'type'>, 'a'>>,
Expect<Equal<UnionPartialProperty<A, '?'>, never>>,
Expect<Equal<MergedUnion<never|undefined>, never|undefined>>,
Expect<Equal<MergedUnion<never>, never>>,
]
type A = { type: 'a'; a: string }
type B = { type: 'b'; b: number }
const func1 = (value: A | B) => {
const { type, a, b } = toMergedUnion(value)
type cases = [
Expect<Equal<typeof type, 'a'|'b'>>,
Expect<Equal<typeof a, string|undefined>>,
Expect<Equal<typeof b, number|undefined>>,
]
}
const func2 = (value?: A | B) => {
const { type, a, b } = toMergedUnion(value) ?? {}
type cases = [
Expect<Equal<typeof type, 'a'|'b'|undefined>>,
Expect<Equal<typeof a, string|undefined>>,
Expect<Equal<typeof b, number|undefined>>,
]
}
@tmatz
Copy link
Author

tmatz commented Aug 7, 2022

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment