Type Alias MergeDeep<Destination, Source, Options>Experimental

MergeDeep: MergeDeepWithDefaultOptions<
    SimplifyDeep<Destination>,
    SimplifyDeep<Source>,
    Options,
>

Merge two objects or two arrays/tuples recursively into a new type.

  • Properties that only exist in one object are copied into the new object.
  • Properties that exist in both objects are merged if possible or replaced by the one of the source if not.
  • Top-level arrays and tuples are always spread.
  • By default, inner arrays and tuples are replaced. See arrayMergeMode option to change this behaviour.
  • By default, individual array/tuple elements are not affected. See recurseIntoArrays option to change this behaviour.

Type Parameters

import type {MergeDeep} from 'type-fest';

type Foo = {
life: number;
items: string[];
a: {b: string; c: boolean; d: number[]};
};

interface Bar {
name: string;
items: number[];
a: {b: number; d: boolean[]};
}

type FooBar = MergeDeep<Foo, Bar>;
// {
// life: number;
// name: string;
// items: number[];
// a: {b: number; c: boolean; d: boolean[]};
// }

type FooBar = MergeDeep<Foo, Bar, {arrayMergeMode: 'spread'}>;
// {
// life: number;
// name: string;
// items: (string | number)[];
// a: {b: number; c: boolean; d: (number | boolean)[]};
// }
import type {MergeDeep} from 'type-fest';

// Merge two arrays
type ArrayMerge = MergeDeep<string[], number[]>; // => (string | number)[]

// Merge two tuples
type TupleMerge = MergeDeep<[1, 2, 3], ['a', 'b']>; // => (1 | 2 | 3 | 'a' | 'b')[]

// Merge an array into a tuple
type TupleArrayMerge = MergeDeep<[1, 2, 3], string[]>; // => (string | 1 | 2 | 3)[]

// Merge a tuple into an array
type ArrayTupleMerge = MergeDeep<number[], ['a', 'b']>; // => (number | 'b' | 'a')[]
import type {MergeDeep, MergeDeepOptions} from 'type-fest';

type Foo = {foo: 'foo'; fooBar: string[]};
type Bar = {bar: 'bar'; fooBar: number[]};

type FooBar = MergeDeep<Foo, Bar>;
// { foo: "foo"; bar: "bar"; fooBar: number[]}

type FooBarSpread = MergeDeep<Foo, Bar, {arrayMergeMode: 'spread'}>;
// { foo: "foo"; bar: "bar"; fooBar: (string | number)[]}

type FooBarArray = MergeDeep<Foo[], Bar[]>;
// (Foo | Bar)[]

type FooBarArrayDeep = MergeDeep<Foo[], Bar[], {recurseIntoArrays: true}>;
// FooBar[]

type FooBarArraySpreadDeep = MergeDeep<Foo[], Bar[], {recurseIntoArrays: true; arrayMergeMode: 'spread'}>;
// FooBarSpread[]

type FooBarTupleDeep = MergeDeep<[Foo, true, 42], [Bar, 'life'], {recurseIntoArrays: true}>;
// [FooBar, 'life', 42]

type FooBarTupleWithArrayDeep = MergeDeep<[Foo[], true], [Bar[], 'life', 42], {recurseIntoArrays: true}>;
// [FooBar[], 'life', 42]
import type {MergeDeep, MergeDeepOptions} from 'type-fest';

function mergeDeep<Destination, Source, Options extends MergeDeepOptions = {}>(
destination: Destination,
source: Source,
options?: Options,
): MergeDeep<Destination, Source, Options> {
// Make your implementation ...
}

This type is marked as experimental because it depends on ConditionalSimplifyDeep which itself is experimental.