{"id":12169,"library":"ts-deepmerge","title":"TypeScript Deep Merge Utility","description":"ts-deepmerge is a TypeScript utility library providing a robust deep merge function. It automatically infers the return type based on input objects without mutating the source objects, a key differentiator from many mutable merge utilities. Objects and arrays are merged recursively, while primitive values like numbers and strings are overwritten. Merging occurs in the order of arguments provided, giving precedence to later arguments. The current stable version is 7.0.3. As a utility library, its release cadence is driven by new features, bug fixes, or TypeScript version updates rather than a strict schedule. It differentiates itself by strong TypeScript type inference and non-mutation by default, supporting both ESM and CommonJS environments. It also offers an `options` mechanism to customize merge behavior, such as how arrays are handled.","status":"active","version":"7.0.3","language":"javascript","source_language":"en","source_url":"git@github.com:voodoocreation/ts-deepmerge","tags":["javascript","typescript","deep","merge","types","ts-merge","ts-deepmerge","merging"],"install":[{"cmd":"npm install ts-deepmerge","lang":"bash","label":"npm"},{"cmd":"yarn add ts-deepmerge","lang":"bash","label":"yarn"},{"cmd":"pnpm add ts-deepmerge","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"This is the primary named export for the deep merge function, supporting both ESM and CommonJS. Use destructuring for CommonJS.","wrong":"const { merge } = require('ts-deepmerge');","symbol":"merge","correct":"import { merge } from 'ts-deepmerge';"},{"note":"The `withOptions` method is a property of the main `merge` function, not a separate named export. It's used to customize merge behavior.","wrong":"import { withOptions } from 'ts-deepmerge';","symbol":"merge.withOptions","correct":"import { merge } from 'ts-deepmerge';\nconst result = merge.withOptions(...);"}],"quickstart":{"code":"import { merge } from 'ts-deepmerge';\n\nconst obj1 = {\n  a: {\n    a: 1\n  },\n  array: [1, 2]\n};\n\nconst obj2 = {\n  b: {\n    a: 2,\n    b: 2\n  },\n  array: [3, 4]\n};\n\nconst obj3 = {\n  a: {\n    b: 3\n  },\n  b: {\n    b: 3,\n    c: 3\n  },\n  c: 3,\n  array: [5, 6]\n};\n\n// Basic deep merge\nconst resultBasic = merge(obj1, obj2, obj3);\nconsole.log('Merged Result (default):', resultBasic);\n/*\n{ a: { a: 1, b: 3 }, b: { a: 2, b: 3, c: 3 }, array: [ 1, 2, 3, 4, 5, 6 ], c: 3 }\n*/\n\n// Merge with options, e.g., to overwrite arrays instead of merging them\nconst resultWithOptions = merge.withOptions(\n  { mergeArrays: false },\n  obj1, \n  obj2\n);\nconsole.log('Merged Result (mergeArrays: false):', resultWithOptions);\n/*\n{ a: { a: 1 }, array: [ 3, 4 ] }\n*/","lang":"typescript","description":"Demonstrates basic deep merging of multiple objects and using `merge.withOptions` to customize array merging behavior."},"warnings":[{"fix":"For generic declared types where the final type is known, explicitly assert the return type using the `as` keyword. For example: `const result = merge(obj1, obj2) as IExpectedType;`","message":"When merging objects with generic declared types/interfaces, TypeScript's inference for `ts-deepmerge` may result in a union type that doesn't perfectly reflect the final merged type, especially if properties are known to be overwritten. This is a current limitation with TypeScript's type inference for functions accepting an infinite number of arguments.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Use `merge.withOptions({ mergeArrays: false }, ...objects)` to configure array merging behavior.","message":"By default, `ts-deepmerge` merges arrays by concatenating them. If you intend for arrays to be overwritten instead of merged, you must explicitly use the `withOptions` method and set `mergeArrays: false`.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"No fix needed, this is intended behavior. Be aware that primitive values in later arguments will replace those in earlier arguments at the same path.","message":"Primitive values (numbers, strings, booleans, null, undefined) are always overwritten in the order of arguments, not merged. Only objects and arrays are deeply merged. Ensure this behavior aligns with expectations for your data structures.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"This specific error isn't directly related to `ts-deepmerge`'s return type inference but rather how you declare your input objects. Ensure your input objects conform to the expected types, or if you're merging a `Partial` into a complete type, use a type assertion on the *result* of the merge if `ts-deepmerge`'s inference produces a union type that's too broad. Example: `const result = merge(obj1, obj2) as IObj;`","cause":"This is a TypeScript error when trying to assign a `Partial<IObj>` directly to `IObj`.","error":"Type 'Partial<IObj>' is not assignable to type 'IObj'. Property 'b' is missing in type 'Partial<IObj>' but required in type 'IObj'."},{"fix":"If you know the final type of the array after merging, use a type assertion on the result of the `merge` call: `const result = merge(obj1, obj2) as { myKey: string[] };` or `const myArray = merge(..., { myArray: [1,2] }) as number[];`.","cause":"This indicates an issue with type inference where `ts-deepmerge` might produce a union type for an array (e.g., `(string | number)[]` or `string[] | number[]`) when a more specific type is expected downstream.","error":"TS2345: Argument of type 'string[] | number[]' is not assignable to parameter of type 'string[]'."}],"ecosystem":"npm"}