npm i merge-anything
Objekte und andere Typen rekursiv zusammenführen. Vollständige TypeScript- Unterstützung! Eine einfache und kleine Integration.
Ich habe dieses Paket erstellt, weil ich viele ähnliche Pakete ausprobiert habe, die Zusammenführung/Deepmerging/rekursive Objektzuweisung usw. durchführen. Aber alle hatten ihre Macken und alle machen Dinge kaputt, die sie nicht kaputt machen sollten ...?
Ich habe gesucht:
Object.assign()
aber tiefgreifend Letzteres ist entscheidend! In JavaScript ist zwar fast alles ein Objekt , aber ich möchte nicht, dass eine Zusammenführungsfunktion versucht, z. B. zusammenzuführen. zwei new Date()
-Instanzen! So viele Bibliotheken verwenden benutzerdefinierte Klassen, die Objekte mit speziellen Prototypen erstellen, und solche Objekte gehen alle kaputt, wenn versucht wird, sie zusammenzuführen. Also müssen wir vorsichtig sein!
merge-anything führt Objekte und verschachtelte Eigenschaften zusammen, jedoch nur, solange es sich um „einfache Objekte“ handelt. Sobald ein Sub-Requisit kein „einfaches Objekt“ ist und über einen speziellen Prototyp verfügt, wird es diese Instanz „wie sie ist“ kopieren. ♻️
import { merge } from 'merge-anything'
const starter = { name : 'Squirtle' , types : { water : true } }
const newValues = { name : 'Wartortle' , types : { fighting : true } , level : 16 }
const evolution = merge ( starter , newValues , { is : 'cool' } )
// returns {
// name: 'Wartortle',
// types: { water: true, fighting: true },
// level: 16,
// is: 'cool'
// }
Wenn Sie im obigen Beispiel TypeScript verwenden und den Mauszeiger über evolution
bewegen, können Sie sofort den Typ Ihres neuen Objekts sehen. Das ist sehr leistungsstark, da Sie Dinge zusammenführen können und TypeScript ohne any
genau weiß, wie Ihre neu zusammengeführten Objekte aussehen!
Der Rückgabetyp der Funktion merge()
kann auch als TypeScript-Dienstprogramm verwendet werden:
import type { Merge } from 'merge-anything'
type A1 = { name : string }
type A2 = { types : { water : boolean } }
type A3 = { types : { fighting : boolean } }
type Result = Merge < A1 , [ A2 , A3 ] >
Dieses Paket durchläuft rekursiv einfache Objekte und führt die Werte in einem neuen Objekt zusammen.
Bitte beachten Sie, dass dieses Paket spezielle JavaScript-Objekte wie Klasseninstanzen erkennt. In solchen Fällen werden sie nicht wie Objekte rekursiv zusammengeführt, sondern die Klasse wird dem neuen Objekt „wie sie ist“ zugewiesen!
// all passed objects do not get modified
const a = { a : 'a' }
const b = { b : 'b' }
const c = { c : 'c' }
const result = merge ( a , b , c )
// a === {a: 'a'}
// b === {b: 'b'}
// c === {c: 'c'}
// result === {a: 'a', b: 'b', c: 'c'}
// However, be careful with JavaScript object references with nested props. See below: A note on JavaScript object references
// arrays get overwritten
// (for "concat" logic, see Extensions below)
merge ( { array : [ 'a' ] } , { array : [ 'b' ] } ) // returns {array: ['b']}
// empty objects merge into objects
merge ( { obj : { prop : 'a' } } , { obj : { } } ) // returns {obj: {prop: 'a'}}
// but non-objects overwrite objects
merge ( { obj : { prop : 'a' } } , { obj : null } ) // returns {obj: null}
// and empty objects overwrite non-objects
merge ( { prop : 'a' } , { prop : { } } ) // returns {prop: {}}
merge-anything hält spezielle Objekte wie Datumsangaben, reguläre Ausdrücke, Funktionen, Klasseninstanzen usw. ordnungsgemäß intakt.
Es ist jedoch sehr wichtig , dass Sie wissen, wie Sie JavaScript-Objektverweise umgehen. Bitte lesen Sie unbedingt den #a-Hinweis zu JavaScript-Objektreferenzen weiter unten.
Das Standardverhalten besteht darin, dass Arrays überschrieben werden. Sie können mergeAndConcat
importieren, wenn Sie Arrays verketten müssen. Aber keine Sorge, wenn Sie dies nicht benötigen, diese Bibliothek ist baumschüttelnd und importiert keinen Code, den Sie nicht verwenden!
import { mergeAndConcat } from 'merge-anything'
mergeAndConcat (
{ nested : { prop : { array : [ 'a' ] } } } ,
{ nested : { prop : { array : [ 'b' ] } } }
)
// returns { nested: { prop: { array: ['a', 'b'] } } },
Es kann vorkommen, dass Sie die Logik anpassen müssen, wenn zwei Dinge zusammengeführt werden. Sie können Ihre eigene benutzerdefinierte Funktion bereitstellen, die jedes Mal ausgelöst wird, wenn ein Wert überschrieben wird.
Für diesen Fall verwenden wir mergeAndCompare
. Hier ist ein Beispiel mit einer Vergleichsfunktion, die Zeichenfolgen verkettet:
import { mergeAndCompare } from 'merge-anything'
function concatStrings ( originVal , newVal , key ) {
if ( typeof originVal === 'string' && typeof newVal === 'string' ) {
// concat logic
return ` ${ originVal } ${ newVal } `
}
// always return newVal as fallback!!
return newVal
}
mergeAndCompare ( concatStrings , { name : 'John' } , { name : 'Simth' } )
// returns { name: 'JohnSmith' }
Hinweis für TypeScript-Benutzer. Der von dieser Funktion zurückgegebene Typ ist möglicherweise nicht korrekt. In diesem Fall müssen Sie das Ergebnis in die von Ihnen bereitgestellte Schnittstelle umwandeln
Seien Sie vorsichtig bei der JavaScript-Objektreferenz. Jede verschachtelte Eigenschaft ist reaktiv und zwischen dem Original und den zusammengeführten Objekten verknüpft! Im Folgenden zeigen wir, wie Sie dies verhindern können.
const original = { airport : { status : 'dep. ?' } }
const extraInfo = { airport : { location : 'Brussels' } }
const merged = merge ( original , extraInfo )
// we change the status from departuring ? to landing ?
merged . airport . status = 'lan. ?'
// the `merged` value will be modified
// merged.airport.status === 'lan. ?'
// However `original` value will also be modified!!
// original.airport.status === 'lan. ?'
Die wichtigste Regel, die Sie sich merken sollten, lautet:
Jede Eigenschaft, die auf mehr als einer Ebene verschachtelt ist und keine überlappende übergeordnete Eigenschaft aufweist, ist sowohl im Zusammenführungsergebnis als auch in der Quelle reaktiv und verknüpft
Es gibt jedoch eine wirklich einfache Lösung . Wir können einfach das Zusammenführungsergebnis kopieren, um jegliche Reaktivität zu beseitigen. Hierfür können wir die Copy-Anything-Bibliothek verwenden. Diese Bibliothek stellt außerdem sicher, dass Instanzen spezieller Klassen nicht kaputt gehen , sodass Sie sie verwenden können, ohne befürchten zu müssen, dass Dinge kaputt gehen!
Sehen Sie unten, wie wir „copy-anything“ integrieren:
import { copy } from 'copy-anything'
const original = { airport : { status : 'dep. ?' } }
const extraInfo = { airport : { location : 'Brussels' } }
const merged = copy ( merge ( original , extraInfo ) )
// we change the status from departuring ? to landing ?
merged . airport . status = 'lan. ?' ( merged . airport . status === 'lan. ?' ) (
// true
// `original` won't be modified!
original . airport . status === 'dep. ?'
) // true
Sie können dann herumspielen, wo Sie die copy()
Funktion platzieren möchten.
Copy Anything wird auch vollständig von TypeScript unterstützt!
Es geht im wahrsten Sinne des Wortes nur darum, ein Objekt rekursiv zu durchlaufen und die Werte einem neuen Objekt wie unten zuzuweisen. Es ist jedoch umschlossen, um zusätzliche Parameter usw. zu ermöglichen. Der folgende Code ist die grundlegende Integration, die Ihnen die Grundlagen der Funktionsweise verdeutlicht.
import { isPlainObject } from 'is-what'
function mergeRecursively ( origin , newComer ) {
if ( ! isPlainObject ( newComer ) ) return newComer
// define newObject to merge all values upon
const newObject = isPlainObject ( origin )
? Object . keys ( origin ) . reduce ( ( carry , key ) => {
const targetVal = origin [ key ]
if ( ! Object . keys ( newComer ) . includes ( key ) ) carry [ key ] = targetVal
return carry
} , { } )
: { }
return Object . keys ( newComer ) . reduce ( ( carry , key ) => {
const newVal = newComer [ key ]
const targetVal = origin [ key ]
// early return when targetVal === undefined
if ( targetVal === undefined ) {
carry [ key ] = newVal
return carry
}
// When newVal is an object do the merge recursively
if ( isPlainObject ( newVal ) ) {
carry [ key ] = mergeRecursively ( targetVal , newVal )
return carry
}
// all the rest
carry [ key ] = newVal
return carry
} , newObject )
}
* Natürlich gibt es kleine Unterschiede zum tatsächlichen Quellcode, um seltene Fälle und zusätzliche Funktionen zu bewältigen. Der eigentliche Quellcode ist hier.