UNPKG

alacritty-theme-switch

Version:
322 lines 11.1 kB
/** * Merges the two given records, recursively merging any nested records with the * second collection overriding the first in case of conflict. * * For arrays, maps and sets, a merging strategy can be specified to either * `replace` values, or `merge` them instead. * * @typeParam T Type of the first record * * @param record First record to merge. * @param other Second record to merge. * @param options Merging options. * * @returns A new record with the merged values. * * @example Merge objects * ```ts * import { deepMerge } from "@std/collections/deep-merge"; * import { assertEquals } from "@std/assert"; * * const a = { foo: true }; * const b = { foo: { bar: true } }; * * const result = deepMerge(a, b); * * const expected = { foo: { bar: true } }; * * assertEquals(result, expected); * ``` * * @example Merge arrays * ```ts * import { deepMerge } from "@std/collections/deep-merge"; * import { assertEquals } from "@std/assert"; * * const a = { foo: [1, 2] }; * const b = { foo: [3, 4] }; * * const result = deepMerge(a, b); * * const expected = { foo: [1, 2, 3, 4] }; * * assertEquals(result, expected); * ``` * * @example Merge maps * ```ts * import { deepMerge } from "@std/collections/deep-merge"; * import { assertEquals } from "@std/assert"; * * const a = { foo: new Map([["a", 1]]) }; * const b = { foo: new Map([["b", 2]]) }; * * const result = deepMerge(a, b); * * const expected = { foo: new Map([["a", 1], ["b", 2]]) }; * * assertEquals(result, expected); * ``` * * @example Merge sets * ```ts * import { deepMerge } from "@std/collections/deep-merge"; * import { assertEquals } from "@std/assert"; * * const a = { foo: new Set([1]) }; * const b = { foo: new Set([2]) }; * * const result = deepMerge(a, b); * * const expected = { foo: new Set([1, 2]) }; * * assertEquals(result, expected); * ``` * * @example Merge with custom options * ```ts * import { deepMerge } from "@std/collections/deep-merge"; * import { assertEquals } from "@std/assert"; * * const a = { foo: [1, 2] }; * const b = { foo: [3, 4] }; * * const result = deepMerge(a, b, { arrays: "replace" }); * * const expected = { foo: [3, 4] }; * * assertEquals(result, expected); * ``` */ export declare function deepMerge<T extends Record<PropertyKey, unknown>>(record: Partial<Readonly<T>>, other: Partial<Readonly<T>>, options?: Readonly<DeepMergeOptions>): T; /** * Merges the two given records, recursively merging any nested records with the * second collection overriding the first in case of conflict. * * For arrays, maps and sets, a merging strategy can be specified to either * `replace` values, or `merge` them instead. * * @typeParam T Type of the first record * @typeParam U Type of the second record * @typeParam Options Merging options * * @param record First record to merge. * @param other Second record to merge. * @param options Merging options. * * @returns A new record with the merged values. * * @example Merge objects * ```ts * import { deepMerge } from "@std/collections/deep-merge"; * import { assertEquals } from "@std/assert"; * * const a = { foo: true }; * const b = { foo: { bar: true } }; * * const result = deepMerge(a, b); * * const expected = { foo: { bar: true } }; * * assertEquals(result, expected); * ``` * * @example Merge arrays * ```ts * import { deepMerge } from "@std/collections/deep-merge"; * import { assertEquals } from "@std/assert"; * * const a = { foo: [1, 2] }; * const b = { foo: [3, 4] }; * * const result = deepMerge(a, b); * * const expected = { foo: [1, 2, 3, 4] }; * * assertEquals(result, expected); * ``` * * @example Merge maps * ```ts * import { deepMerge } from "@std/collections/deep-merge"; * import { assertEquals } from "@std/assert"; * * const a = { foo: new Map([["a", 1]]) }; * const b = { foo: new Map([["b", 2]]) }; * * const result = deepMerge(a, b); * * const expected = { foo: new Map([["a", 1], ["b", 2]]) }; * * assertEquals(result, expected); * ``` * * @example Merge sets * ```ts * import { deepMerge } from "@std/collections/deep-merge"; * import { assertEquals } from "@std/assert"; * * const a = { foo: new Set([1]) }; * const b = { foo: new Set([2]) }; * * const result = deepMerge(a, b); * * const expected = { foo: new Set([1, 2]) }; * * assertEquals(result, expected); * ``` * * @example Merge with custom options * ```ts * import { deepMerge } from "@std/collections/deep-merge"; * import { assertEquals } from "@std/assert"; * * const a = { foo: [1, 2] }; * const b = { foo: [3, 4] }; * * const result = deepMerge(a, b, { arrays: "replace" }); * * const expected = { foo: [3, 4] }; * * assertEquals(result, expected); * ``` */ export declare function deepMerge<T extends Record<PropertyKey, unknown>, U extends Record<PropertyKey, unknown>, Options extends DeepMergeOptions>(record: Readonly<T>, other: Readonly<U>, options?: Readonly<Options>): DeepMerge<T, U, Options>; /** Merging strategy */ export type MergingStrategy = "replace" | "merge"; /** Options for {@linkcode deepMerge}. */ export type DeepMergeOptions = { /** * Merging strategy for arrays * * @default {"merge"} */ arrays?: MergingStrategy; /** * Merging strategy for maps. * * @default {"merge"} */ maps?: MergingStrategy; /** * Merging strategy for sets. * * @default {"merge"} */ sets?: MergingStrategy; }; /** * How does recursive typing works ? * * Deep merging process is handled through `DeepMerge<T, U, Options>` type. * If both T and U are Records, we recursively merge them, * else we treat them as primitives. * * Merging process is handled through `Merge<T, U>` type, in which * we remove all maps, sets, arrays and records so we can handle them * separately depending on merging strategy: * * Merge< * {foo: string}, * {bar: string, baz: Set<unknown>}, * > // "foo" and "bar" will be handled with `MergeRightOmitComplexes` * // "baz" will be handled with `MergeAll*` type * * `MergeRightOmitComplexes<T, U>` will do the above: all T's * exclusive keys will be kept, though common ones with U will have their * typing overridden instead: * * MergeRightOmitComplexes< * {foo: string, baz: number}, * {foo: boolean, bar: string} * > // {baz: number, foo: boolean, bar: string} * // "baz" was kept from T * // "foo" was overridden by U's typing * // "bar" was added from U * * For Maps, Arrays, Sets and Records, we use `MergeAll*<T, U>` utility * types. They will extract relevant data structure from both T and U * (providing that both have same data data structure, except for typing). * * From these, `*ValueType<T>` will extract values (and keys) types to be * able to create a new data structure with an union typing from both * data structure of T and U: * * MergeAllSets< * {foo: Set<number>}, * {foo: Set<string>} * > // `SetValueType` will extract "number" for T * // `SetValueType` will extract "string" for U * // `MergeAllSets` will infer type as Set<number|string> * // Process is similar for Maps, Arrays, and Sets * * `DeepMerge<T, U, Options>` is taking a third argument to be handle to * infer final typing depending on merging strategy: * * & (Options extends { sets: "replace" } ? PartialByType<U, Set<unknown>> * : MergeAllSets<T, U>) * * In the above line, if "Options" have its merging strategy for Sets set to * "replace", instead of performing merging of Sets type, it will take the * typing from right operand (U) instead, effectively replacing the typing. * * An additional note, we use `ExpandRecursively<T>` utility type to expand * the resulting typing and hide all the typing logic of deep merging so it is * more user friendly. */ /** Force intellisense to expand the typing to hide merging typings */ export type ExpandRecursively<T> = T extends Record<PropertyKey, unknown> ? T extends infer O ? { [K in keyof O]: ExpandRecursively<O[K]>; } : never : T; /** Filter of keys matching a given type */ export type PartialByType<T, U> = { [K in keyof T as T[K] extends U ? K : never]: T[K]; }; /** Get set values type */ export type SetValueType<T> = T extends Set<infer V> ? V : never; /** Merge all sets types definitions from keys present in both objects */ export type MergeAllSets<T, U, X = PartialByType<T, Set<unknown>>, Y = PartialByType<U, Set<unknown>>, Z = { [K in keyof X & keyof Y]: Set<SetValueType<X[K]> | SetValueType<Y[K]>>; }> = Z; /** Get array values type */ export type ArrayValueType<T> = T extends Array<infer V> ? V : never; /** Merge all sets types definitions from keys present in both objects */ export type MergeAllArrays<T, U, X = PartialByType<T, Array<unknown>>, Y = PartialByType<U, Array<unknown>>, Z = { [K in keyof X & keyof Y]: Array<ArrayValueType<X[K]> | ArrayValueType<Y[K]>>; }> = Z; /** Get map values types */ export type MapKeyType<T> = T extends Map<infer K, unknown> ? K : never; /** Get map values types */ export type MapValueType<T> = T extends Map<unknown, infer V> ? V : never; /** Merge all sets types definitions from keys present in both objects */ export type MergeAllMaps<T, U, X = PartialByType<T, Map<unknown, unknown>>, Y = PartialByType<U, Map<unknown, unknown>>, Z = { [K in keyof X & keyof Y]: Map<MapKeyType<X[K]> | MapKeyType<Y[K]>, MapValueType<X[K]> | MapValueType<Y[K]>>; }> = Z; /** Merge all records types definitions from keys present in both objects */ export type MergeAllRecords<T, U, Options, X = PartialByType<T, Record<PropertyKey, unknown>>, Y = PartialByType<U, Record<PropertyKey, unknown>>, Z = { [K in keyof X & keyof Y]: DeepMerge<X[K], Y[K], Options>; }> = Z; /** Exclude map, sets and array from type */ export type OmitComplexes<T> = Omit<T, keyof PartialByType<T, Map<unknown, unknown> | Set<unknown> | Array<unknown> | Record<PropertyKey, unknown>>>; /** Object with keys in either T or U but not in both */ export type ObjectXorKeys<T, U, X = Omit<T, keyof U> & Omit<U, keyof T>, Y = { [K in keyof X]: X[K]; }> = Y; /** Merge two objects, with left precedence */ export type MergeRightOmitComplexes<T, U, X = ObjectXorKeys<T, U> & OmitComplexes<{ [K in keyof U]: U[K]; }>> = X; /** Merge two objects */ export type Merge<T, U, Options, X = MergeRightOmitComplexes<T, U> & MergeAllRecords<T, U, Options> & (Options extends { sets: "replace"; } ? PartialByType<U, Set<unknown>> : MergeAllSets<T, U>) & (Options extends { arrays: "replace"; } ? PartialByType<U, Array<unknown>> : MergeAllArrays<T, U>) & (Options extends { maps: "replace"; } ? PartialByType<U, Map<unknown, unknown>> : MergeAllMaps<T, U>)> = ExpandRecursively<X>; /** Merge deeply two objects */ export type DeepMerge<T, U, Options = Record<string, MergingStrategy>> = [ T, U ] extends [Record<PropertyKey, unknown>, Record<PropertyKey, unknown>] ? Merge<T, U, Options> : T | U; //# sourceMappingURL=deep_merge.d.ts.map