Vue Patch Object Implementation
Vue.js provides a powerful mechanism for managing and updating component data reactively. A common pattern is to update a complex object by providing a "patch" object, which specifies only the parts of the original object that need to be changed. This challenge asks you to implement a function that simulates this Vue.js patching behavior in TypeScript.
Problem Description
Your task is to create a TypeScript function named patchObject that takes two arguments:
target: The original object to be patched.patch: An object containing the properties and their new values that should be applied to thetargetobject.
The function should return a new object that represents the patched version of the target object. This means:
- Properties present in
patchshould overwrite their corresponding properties intarget. - Properties not present in
patchshould retain their original values fromtarget. - If a property in
patchisundefined, it should be treated as a valid value and overwrite the corresponding property intarget(similar to howObject.assignbehaves). - The function should handle nested objects. If a property in
patchis an object and its corresponding property intargetis also an object, the function should recursively patch the nested object. - The original
targetobject must not be mutated. The function should return a completely new object.
Examples
Example 1:
Input:
target = {
name: "Alice",
age: 30,
address: {
street: "123 Main St",
city: "Anytown"
}
}
patch = {
age: 31,
address: {
city: "Otherville"
}
}
Output:
{
name: "Alice",
age: 31,
address: {
street: "123 Main St",
city: "Otherville"
}
}
Explanation:
The 'age' property is updated to 31.
The 'address' object is patched: 'city' is updated to "Otherville", while 'street' remains unchanged.
The 'name' property is not in the patch and remains "Alice".
Example 2:
Input:
target = {
id: 1,
settings: {
theme: "dark",
notifications: true
}
}
patch = {
settings: {
notifications: false,
language: "en"
},
isActive: true
}
Output:
{
id: 1,
settings: {
theme: "dark",
notifications: false,
language: "en"
},
isActive: true
}
Explanation:
The 'settings' object is patched: 'notifications' is updated, and 'language' is added. 'theme' is retained.
The 'isActive' property is new and added to the root object.
The 'id' property is retained.
Example 3: Handling undefined and non-object types
Input:
target = {
value: 10,
config: {
enabled: true,
threshold: 5
},
optional: "present"
}
patch = {
value: undefined,
config: {
enabled: false,
threshold: null // null is a valid value
},
optional: undefined, // undefined should overwrite
newField: "added"
}
Output:
{
value: undefined,
config: {
enabled: false,
threshold: null
},
optional: undefined,
newField: "added"
}
Explanation:
'value' is set to undefined.
'config' is patched: 'enabled' becomes false, 'threshold' becomes null.
'optional' is set to undefined, overwriting its previous value.
'newField' is added.
Constraints
- The
targetandpatchobjects can have arbitrary levels of nesting. - The function should be efficient, ideally performing a shallow copy for non-nested properties and a deep copy only where necessary.
- Input types for
targetandpatchwill always beRecord<string, any>or a subtype thereof. - The function should return
Record<string, any>or a subtype thereof.
Notes
- Consider how to differentiate between an object that needs to be deeply patched and other object types (like Dates, Arrays, etc.). For this challenge, assume that only plain JavaScript objects (
typeof value === 'object' && value !== null && !Array.isArray(value)) should be recursively patched. Other object types should be treated as primitive values and overwritten directly. - Think about how to iterate through the properties of both the
targetandpatchobjects. - The core of the challenge lies in correctly handling the recursive patching of nested objects while ensuring immutability.