I have a question about the behavior of the delete
keyword in JavaScript or TypeScript.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete
What I need is a way of picking properties from an Object and a way of omitting properties from an Object.
TypeScript comes with a build in type Pick
https://www.typescriptlang.org/docs/handbook/advanced-types.html
type Pick<T, K extends keyof T> = { [P in K]: T[P]; }
The opposite of Pick
is Omit
, which can be implemented like this:
export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
I also wrote some methods for it that take an object and an Array of properties from that object those properties will be picked or omitted from the object.
export let pickMany = <T, K extends keyof T>(entity: T, props: K[]) => {
return props.reduce((s, prop) => (s[prop] = entity[prop], s) , {} as
Pick<T, K>)
}
export let omitMany = <T, K extends keyof T>(entity: T, props: K[]):
Omit<T, K> => {
return props.reduce((s, prop) => (delete s[prop] ,s), entity)
}
For Omit I used the delete keyword, at the beginning it seem to work but now I am running into some issues. The main issue is that for omitMany
the original object is modified. Which causes problems with preserving the original data and preserving state later in my program.
I have written a simple example to illustrate my problem:
// First I make some interface that contains some structure for data
interface SomeObject { x: string, y: number, z: boolean }
// Initialize object1 with properties x, y and z, containing the important data
// I want to preserve all the data in object1 through the entire program
let object1: SomeObject = { x: "something", y: 0, z: false }
// I can print all properties of object1
console.log(`Object 1: x = ${object1.x}, y = ${object1.y}, z = ${object1.z}`)
// OUTPUT: "Object 1: x = something, y = 0, z = false"
// omit or delete property 'x' from object 1, defining object 2
let object2 = omitMany(object1, ["x"]) // The type of object2 is: {y: number, z: boolean}
// Here I can only get properties z and y, because x has been omitted
// Calling: object2.x gives an compile error
console.log(`Object 2: y = ${object2.y}, z = ${object2.z}`)
// OUTPUT: Object 2: y = 0, z = false (as expected)
// Everything works fine from here, but...
// When I recall omitMany on object1 the following happens:
// Initialize object3 from object1, removing 'x' from an object where x = undefined
let object3 = omitMany(object1, ["x"]) // This code compiles, omitting 'x' from object2 gives an compiler error
//Printing object3 does show no problems, since it satisfies the expected result. Remove 'x' and keep 'y' and 'z'
console.log(`Object 3: y = ${object3.y}, z = ${object3.z}`)
// OUTPUT: Object 3: y = 0, z = false
// But when I print object1 again
console.log(`Object 1: x = ${object1.x}, y = ${object1.y}, z = ${object1.z}`)
// OUTPUT: Object 1: x = undefined, y = 0, z = false
// We lost the data of 'x'!!!
// I also ran into problems when I try to pick property 'x' from the original object1
let object4 = pickMany(object1, ["x"]) // The type of object4 is {x: string}
// When I print 'x' from object4 it is still undefined
console.log(`Object 4: x = ${object4.x}`)
// OUTPUT: Object 4: x = undefined
I understand that this has to do with the behaviour of delete
, but is there an other way to remove properties from an object without loosing the information of the original object? So with preserving all the values and properties.
This problem can be solved with a temporary variable, but I first wanted to see if there are other solutions.