简体   繁体   English

除了使用“删除”之外,还有其他方法可以从对象中删除属性吗?

[英]Is there an other way to remove a property from an object than with “delete”?

I have a question about the behavior of the delete keyword in Javascript or Typescript. 我对Javascript或Typescript中delete关键字的行为有疑问。 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete 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 omiting properties from an Object. 我需要的是一种从对象中选择属性的方法,以及从对象中忽略属性的方法。

Typescript comes with a build in type Pick https://www.typescriptlang.org/docs/handbook/advanced-types.html Typescript带有一个类型为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 , wich can be implementend like this: Pick的相反是Omit ,可以这样实现:

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 omited 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. 对于Omit,我使用了delete关键字,一开始它似乎可以工作,但是现在我遇到了一些问题。 The main issue is that for omitMany the original object is modified. 主要问题是,对于omitMany ,原始对象已被修改。 Wich causes problems with preserving the original data and preserving state later in my program. Wich在我的程序中保存原始数据和保存状态会引起问题。

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 throug 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 omited
// 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, omiting '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? 我知道这与delete的行为有关,但是还有另一种方法可以从对象中删除属性而不丢失原始对象的信息吗? 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. 这个问题可以用一个临时变量来解决,但是我首先想看看是否还有其他解决方案。

This is how I solved this: 这就是我解决的方法:

// https://stackoverflow.com/a/49579497/14357
/** Extracts optional keys from T */
export type OptionalKeys<T> = {
    [K in keyof T]-?: ({} extends {
        [P in K]: T[K];
    } ? K : never);
}[keyof T];

/** Typesafe way to delete optional properties from an object using magic of OptionalKeys<T> */
export const deleteOptionalProperty = <T>(obj: T, id: OptionalKeys<T>): T => {
    const { [id]: deleted, ...newState } = obj;
    return newState as T // this type-conversion is safe because we're sure we only deleted optional props
}

export const deleteOptionalProperties = <T>(obj: T, ...ids: OptionalKeys<T>[]): T =>
    ids.reduce((prev, id) => deleteOptionalProperty(prev, id), obj)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM