Hacker News new | ask | show | jobs
by Benjamin_Dobell 1362 days ago
This fails on:

  const result = merge({ a: 1 }, { a: "fdsfsd" })
The correct type is quite complex and depends on whether or not `exactOptionalPropertyTypes` is enabled.

EDIT: I think this is correct for when `exactOptionalPropertyTypes` is off.

  type OptionalKeys<T extends { [key in symbol | string | number]?: unknown }> = { [K in keyof T]: {} extends Pick<T, K> ? K : never }[keyof T]

  function merge<
    A extends { [K in symbol | string | number]?: unknown },
    B extends { [K in symbol | string | number]?: unknown },
  >(a: A, b: B): {
    [K in Exclude<keyof B, keyof A>]: B[K]
    } & {
      [K in Exclude<keyof A, keyof B>]: A[K]
    } & {
      [K in keyof A & keyof B]: K extends OptionalKeys<B> ? A[K] | Exclude<B[K], undefined> : B[K];
    }
That's for when `exactOptionPropertyTypes` is enabled. With it disabled, then you'd replace `Exclude<B[K], undefined>` with `B[K]`.

As to whether this is a good idea. Ah... it's not :P

1 comments

Wow yeah it gets way too complex if you want to track the types of properties within the objects too! If that is the case, then I would just prefer to do this instead as it is much simpler:

  type Value = { a: string }
  const result = merge<Value, Value>({ a: 1 }, { a: "fdsfsd" })