deno_std icon indicating copy to clipboard operation
deno_std copied to clipboard

[feature request(collections)] option to merge `undefined` in `deepMerge`

Open scarf005 opened this issue 1 year ago • 4 comments

Is your feature request related to a problem? Please describe.

when merging together deeply nested object (e.g react state), it's important to get 'nonempty' values when merging 'empty' values with 'nonempty' values.

for array, map and set it defaults to merging empty and non-empty values together:

deepMerge({ a: new Set([1]) }, { a: new Set() })
//=> { a: Set(1) { 1 } }

however, it doesn't work with nullish values. it'd be very useful to be able to output non-nullish value from merging nullish and non-nullish value together.

deepMerge({ a: 1 }, { a: undefined })
//=> { a: undefined }
// expected: { a: 1 }

Describe the solution you'd like

in DeepMergeOptions, add nullish: MergingStrategy that controls whether deepMerge will choose non-nullish value over nullish ones, such that

type State = {
  pos: {
    x: number
    y: number
  }
}
type UpdateState = Partial<{
  pos: Partial<{ 
    x: number
    y: number 
  }>
}>

const merge = (state: State, newState: UpdateState): State => deepMerge(state, newState, { nullish: "merge" })

always holds. (currently the return type of merge will be UpdateState)

Describe alternatives you've considered

make nullish: "merge” as default. this may cause breaking changes.

scarf005 avatar May 16 '24 08:05 scarf005

Does nullish: "merge" mean that null also has the same effect as undefined in the above context?

kt3k avatar May 16 '24 10:05 kt3k

Does nullish: "merge" mean that null also has the same effect as undefined in the above context?

yes, it could have been nullish: "replace" | "mergeBoth" | "mergeNull" | "mergeUndefined" but the type would be too complex.

scarf005 avatar May 16 '24 10:05 scarf005

How about only doing this for undefined? (The option would be undefined: "replace" | "ignore"

Handling null in the same way feel a bit strange to me as { a: null } is not assignable to Partial<{ a: number }> for example.

kt3k avatar May 17 '24 05:05 kt3k

sure, since Partial only works with undefined.

scarf005 avatar May 17 '24 05:05 scarf005