diff --git a/src/deepmerge.ts b/src/deepmerge.ts index e25ed3d..6763c58 100644 --- a/src/deepmerge.ts +++ b/src/deepmerge.ts @@ -25,7 +25,7 @@ export default function deepmerge], + Ts extends readonly [object, ...ReadonlyArray], O extends Options = object >(objects: [...Ts], options?: O): DeepMergeAll> @@ -38,7 +38,7 @@ export function deepmergeAll< export function deepmergeAll(objects: ReadonlyArray, options?: Options): object export function deepmergeAll(objects: ReadonlyArray, options?: Options): object { if (!Array.isArray(objects)) { - throw new Error(`first argument should be an array`) + throw new TypeError(`first argument should be an array`) } return objects.reduce((prev, next) => deepmergeImpl(prev, next, getFullOptions(options)), {}) diff --git a/src/impl.ts b/src/impl.ts index c4829be..b043670 100644 --- a/src/impl.ts +++ b/src/impl.ts @@ -7,7 +7,7 @@ function emptyTarget(value: unknown) { export function cloneUnlessOtherwiseSpecified(value: T, options: FullOptions): T { return options.clone !== false && options.isMergeable(value) - ? (deepmergeImpl(emptyTarget(value), value, options) as T) + ? deepmergeImpl(emptyTarget(value), value, options) as T : value } @@ -30,7 +30,7 @@ function getKeys(target: object): Array { function propertyIsOnObject(object: object, property: Property): boolean { try { return property in object - } catch (_) { + } catch { return false } } @@ -101,17 +101,17 @@ export function deepmergeImpl if (!sourceAndTargetTypesMatch) { return cloneUnlessOtherwiseSpecified(source, options) as DeepMerge> - } else if (sourceIsArray) { + } + if (sourceIsArray) { return options.arrayMerge( target as Array, source as Array, options, ) as DeepMerge> - } else { - return mergeObject( + } + return mergeObject( target as Record, source as Record, options, - ) as DeepMerge> - } + ) as DeepMerge> } diff --git a/src/options.ts b/src/options.ts index 3a77b14..016f4c5 100644 --- a/src/options.ts +++ b/src/options.ts @@ -7,32 +7,32 @@ import type { FlattenAlias, Property } from "./types" * Deep merge options. */ export type Options = Partial<{ - arrayMerge?: ArrayMerge - clone?: boolean - customMerge?: ObjectMerge - isMergeable?: IsMergeable + readonly arrayMerge?: ArrayMerge + readonly clone?: boolean + readonly customMerge?: ObjectMerge + readonly isMergeable?: IsMergeable }> /** * Deep merge options with explicit keys. */ export type ExplicitOptions = { - [K in keyof Options]-?: undefined extends O[K] ? never : O[K] + readonly [K in keyof Options]-?: undefined extends O[K] ? never : O[K] } /** * Deep merge options with defaults applied. */ export type FullOptions = FlattenAlias<{ - arrayMerge: O[`arrayMerge`] extends undefined + readonly arrayMerge: O[`arrayMerge`] extends undefined ? typeof defaultArrayMerge : NonNullable - clone: O[`clone`] extends undefined ? true : NonNullable - customMerge?: O[`customMerge`] - isMergeable: O[`isMergeable`] extends undefined + readonly clone: O[`clone`] extends undefined ? true : NonNullable + readonly customMerge?: O[`customMerge`] + readonly isMergeable: O[`isMergeable`] extends undefined ? typeof defaultIsMergeable : NonNullable - cloneUnlessOtherwiseSpecified: (value: T, options: FullOptions) => T + readonly cloneUnlessOtherwiseSpecified: (value: T, options: FullOptions) => T }> /** diff --git a/src/types.ts b/src/types.ts index 3775307..ce9be99 100644 --- a/src/types.ts +++ b/src/types.ts @@ -4,9 +4,9 @@ import type { Options } from "./options" * Deep merge 1 or more types given in an array. */ export type DeepMergeAll< - Ts extends readonly [any, ...Array], + Ts extends readonly [any, ...ReadonlyArray], O extends Options -> = Ts extends readonly [infer T1, ...Array] +> = Ts extends readonly [infer T1, ...ReadonlyArray] ? Ts extends readonly [T1, infer T2, ...infer TRest] ? TRest extends ReadonlyArray ? DeepMerge @@ -81,6 +81,7 @@ type DeepMergeObjectPropsCustom = ReturnType< * * Cannot get return type from arrayMerge passing generics. * TypeScript does not yet support higher order types. + * * @see https://github.com/Microsoft/TypeScript/issues/1213 */ type DeepMergeArrays = IsUndefinedOrNever extends true diff --git a/test/merge-all.ts b/test/merge-all.ts index 5f7b004..b299ea1 100644 --- a/test/merge-all.ts +++ b/test/merge-all.ts @@ -4,7 +4,7 @@ import test from "tape" test(`throw error if first argument is not an array`, (t) => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment, @typescript-eslint/prefer-ts-expect-error -- FIXME: Can't use @ts-expect-error due to it failing in tests. // @ts-ignore Expect a type error when calling the function incorrectly. - t.throws(deepmergeAll.bind(null, { example: true }, { another: `2` }), Error) + t.throws(deepmergeAll.bind(null, { example: true }, { another: `2` }), TypeError) t.end() })