Skip to content

Instantly share code, notes, and snippets.

@ryangoree
Last active June 4, 2024 18:19
Show Gist options
  • Save ryangoree/476ded53f243e02bed77719a91ec4187 to your computer and use it in GitHub Desktop.
Save ryangoree/476ded53f243e02bed77719a91ec4187 to your computer and use it in GitHub Desktop.
Merge the keys of a union or intersection of objects into a single type.
/**
* Merge the keys of a union or intersection of objects into a single type.
*
* @example
* ```ts
* type GetBlockOptions = {
* includeTransactions?: boolean | undefined
* } & (
* | {
* blockHash?: string | undefined;
* blockNumber?: never | undefined;
* blockTag?: never | undefined;
* }
* | {
* blockHash?: never | undefined;
* blockNumber?: bigint | undefined;
* blockTag?: never | undefined;
* }
* | {
* blockHash?: never | undefined;
* blockNumber?: never | undefined;
* blockTag?: string | undefined;
* }
* )
*
* type Merged = MergeKeys<GetBlockOptions>;
* // {
* // includeTransactions?: boolean | undefined;
* // blockHash?: string | undefined;
* // blockNumber?: bigint | undefined;
* // blockTag?: string | undefined;
* // }
* ```
*/
export type MergeKeys<T> =
UnionToIntersection<T> extends infer I
? {
// Each key of the intersection is first checked against the union type,
// T. If it exists in every member of T, then T[K] will be a union of
// the value types. Otherwise, I[K] is used. I[K] is the value type of
// the key in the intersection which will be `never` for keys with
// conflicting value types.
[K in keyof I]: K extends keyof T ? T[K] : I[K];
}
: never;
// https://gist.github.com/ryangoree/e816db56e5fc12aab14e64cea415436c
type UnionToIntersection<T> = (
T extends any ? (member: T) => any : never
) extends (member: infer R) => any
? R
: never;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment