Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delete a dynamic key from a TypeScript object

In TypeScript it is quite simple to clone an object:

const a = {...b}

or clone and update

const a = {...b, c: 'd'}

So for example, I have this code:

const a = {
    'something': 1,
    'e': 2,
};
const c = 'something';
delete a[c];

Is there a nice way to delete a property of that object, instead of using the traditional delete a[c] way? (of course also not a[c] = undefined)

like image 870
Nguyen Phong Thien Avatar asked Feb 18 '19 14:02

Nguyen Phong Thien


2 Answers

You're looking for combination of computed property names and destructuring. More info here

const a = {
    'something': 1,
    'e': 2,
};

const c = 'something';

const { [c]: _, ...withoutC } = a;

Here we're putting value of property something (taken from c variable) into _ variable and all the other props go to withoutC variable. The fact that c defined as const allows typescript to infer the type of withoutC properly.

like image 139
Aleksey L. Avatar answered Sep 30 '22 15:09

Aleksey L.


Rather than deleting the property from a, use destructured assignment to create a new object without that property:

const {c, ...b} = a;

After this b will contain all members of a except c.

Given that a is some type, say, { c: string, d: string } the types of c and b will be inferred to be string and { d: string } respectively. Of course, if you have to explicitly write these type annotations, using an Omit type as @Nurbol Alpybayev suggests is usually a lot better than having to spell out the types in long form.

You can rename c to avoid conflicts with another name using this syntax:

const {c: someOtherName, ...b} = a;

The above method will work if you know the property name at compile time. If that's not the case in your scenario, then the TypeScript compiler can't really help you that much because it won't be able to determine the result type of the operation.

You'd be better off typing a as { [k: string]: number }, in which case delete a[c] would be fine, or you could use something like the following:

const exclude = <T>(map: { [k: string]: T }, omitted: string[]): { [k: string]: T } =>
  return Object.getOwnPropertyNames(a)
    .filter(k => omitted.indexOf(k) >= 0)
    .reduce((a, k) => (a[k] = map[k], a), {})
};
var b = exclude(a, ["c"]);
like image 45
p.s.w.g Avatar answered Sep 30 '22 14:09

p.s.w.g