javascript - 除了 "delete"之外,还有其他方法可以从对象中删除属性吗?

标签 javascript typescript properties preserve

我对 delete 的行为有疑问JavaScript 或 TypeScript 中的关键字。 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete

我需要的是一种从对象中选取属性的方法以及一种从对象中省略属性的方法。

TypeScript 附带一个内置类型 Pick https://www.typescriptlang.org/docs/handbook/advanced-types.html

type Pick<T, K extends keyof T> = { [P in K]: T[P]; }

Pick 相反是 Omit ,可以这样实现:

export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>

我还为其编写了一些方法,这些方法采用一个对象和该对象的属性数组,这些属性将从对象中选取或省略。

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)
 }

对于 Omit,我使用了删除关键字,一开始它似乎有效,但现在我遇到了一些问题。主要问题是 omitMany原始对象被修改。这会导致在程序中保留原始数据和保留状态时出现问题。

我写了一个简单的例子来说明我的问题:

// 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

我知道这与 delete 的行为有关,但是有没有其他方法可以从对象中删除属性而不丢失原始对象的信息?因此,保留所有值和属性。

这个问题可以用临时变量来解决,但我首先想看看是否还有其他解决方案。

最佳答案

这就是我解决这个问题的方法:

// 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)

关于javascript - 除了 "delete"之外,还有其他方法可以从对象中删除属性吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56039176/

相关文章:

Javascript 获取 Array.forEach 的引用

typescript - 需要抽象属性的抽象类

java - 从 .config 文件中读取更新的值

.net - VB.NET函数以字符串形式获取属性名称

javascript - 未捕获的类型错误 : Cannot read property 'checked' of null index. html:24

javascript - 滚动事件触发,但没有scrollTop或offset.top值

javascript - map 未按正确顺序返回对象?

javascript - 为什么我的 AdMob 横幅广告在 Expo Client 中显示,但在最终版本中却没有显示?

javascript - Ionic 2 **panup** 和 **pandown** 事件不起作用

node.js - 我如何将 commander (npm) 与 TypeScript 一起使用?