remeda
Version:
A utility library for JavaScript and Typescript.
1 lines • 3.14 kB
Source Map (JSON)
{"version":3,"file":"mergeAll.cjs","names":[],"sources":["../src/mergeAll.ts"],"sourcesContent":["import type {\n EmptyObject,\n Merge,\n SharedUnionFields,\n Simplify,\n} from \"type-fest\";\nimport type { DisjointUnionFields } from \"./internal/types/DisjointUnionFields\";\nimport type { IterableContainer } from \"./internal/types/IterableContainer\";\nimport type { NonEmptyArray } from \"./internal/types/NonEmptyArray\";\nimport type { TupleParts } from \"./internal/types/TupleParts\";\n\n/**\n * Merge a tuple of object types, where props from later objects override earlier props.\n */\ntype MergeTuple<\n T extends IterableContainer,\n Result = object, // no-op for the first iteration in the successive merges, also infers object as type by default if an empty tuple is used\n> = T extends readonly [infer Head, ...infer Rest]\n ? MergeTuple<Rest, Merge<Result, Head>>\n : Result;\n\n// In the context of a heterogeneous array, the array may not have objects from every type of the union.\n// This means some fields may be missing in the final object, so we make them optional.\n// If there is a non-optional field shared among all members of the union, then we know that if the array is not empty, the field must be present and avoid becoming optional.\n// If the field is already optional, this doesn't really matter.\n// If the array is empty, we know that the loop won't run so we'll just get the empty object.\n// Since we don't know the order of the items in the array, when we merge common fields, we don't know what the final type for the field will be, but we do know that it is one of the many possible types that are available across the members of the union for that field.\n// We represent these possibilities by combining the field's different types across the union members into a union.\ntype MergeUnion<T extends object> = Simplify<\n SharedUnionFields<T> & Partial<DisjointUnionFields<T>>\n>;\n\ntype MergeAll<T extends IterableContainer<object>> =\n // determine if it's a tuple or array\n TupleParts<T> extends { item: never }\n ? T extends readonly []\n ? EmptyObject\n : MergeTuple<T>\n : MergeUnion<T[number]> | EmptyObject;\n\n/**\n * Merges a list of objects into a single object.\n *\n * @param objects - The array of objects.\n * @returns A new object merged with all of the objects in the list. If the list is empty, an empty object is returned.\n * @signature\n * R.mergeAll(objects)\n * @example\n * R.mergeAll([{ a: 1, b: 1 }, { b: 2, c: 3 }, { d: 10 }]) // => { a: 1, b: 2, c: 3, d: 10 }\n * R.mergeAll([]) // => {}\n * @dataFirst\n * @category Array\n */\nexport function mergeAll<T extends object>(\n objects: Readonly<NonEmptyArray<T>>,\n): MergeUnion<T>;\nexport function mergeAll<T extends IterableContainer<object>>(\n objects: T,\n): MergeAll<T>;\nexport function mergeAll(objects: ReadonlyArray<object>): object {\n let out = {};\n\n for (const item of objects) {\n out = { ...out, ...item };\n }\n\n return out;\n}\n"],"mappings":"AA2DA,SAAgB,EAAS,EAAwC,CAC/D,IAAI,EAAM,EAAE,CAEZ,IAAK,IAAM,KAAQ,EACjB,EAAM,CAAE,GAAG,EAAK,GAAG,EAAM,CAG3B,OAAO"}