Agung
Agung

Reputation: 13803

how to delete a property from an object in Typescript without the operand of a 'delete' operator must be optional error?

I have tried to read how to delete a property from an object in here: How do I remove a property from a JavaScript object?

it should use delete, I try it like this

const eventData = {...myEvent}; // myEvent is an instance of my `Event` class
delete eventData.coordinate; // I have error in here

but I have error like this

enter image description here

The operand of a 'delete' operator must be optional.ts(2790)

and then I read this : Typescript does not infer about delete operator and spread operator?

it seems to remove that error is by changing my tsconfig.json file using

{
  "compilerOptions": {
    ...
     "strictNullChecks": false, 
    }
    ...
}

but if I implement this, I will no longer have null checking

so how to delete a property from an object in Typescript without the operand of a 'delete' operator must be optional error?

Upvotes: 19

Views: 34447

Answers (7)

Jam
Jam

Reputation: 13

@Loïc Goyet's solution also works when using an array of properties as input:

function popProperty<T extends Record<string, unknown>, K extends keyof T>(
  obj: T,
  properties: K[],
): Omit<T, K> {
  const result = { ...obj };
  for (const key of properties) {
    delete result[key];
  }
  return result;
}

const x = popProperty({ a: 1, b: 2, c: 3 }, ['a', 'b']);
// const x: Omit<{
//   a: number;
//   b: number;
//   c: number;
// }, "a" | "b">

Upvotes: 0

Andrew Schreiber
Andrew Schreiber

Reputation: 14890

Avoid the error by casting to any:

const user = {
    firstName: 'billy',
    middleName: 'the',
    lastName: 'kid'
};

delete (user as any).middleName

console.log(user)
// { firstName: 'billy', lastName: 'kid' }

Upvotes: 1

Bill
Bill

Reputation: 73

As many people has already pointed out, the following is a workable but not recommending way as it is not type-safe:

/* eslint-disable @typescript-eslint/no-explicit-any */
delete (eventData as any).coordinate;

Upvotes: -3

Lo&#239;c Goyet
Lo&#239;c Goyet

Reputation: 750

Personally, I created a specific function taking advantage of generics, and it worked well!

const removeAttrFromObject = <O extends object, A extends keyof O>(
  object: O,
  attr: A
): Omit<O, A> => {
  const newObject = { ...object }

  if (attr in newObject) {
    delete newObject[attr]
  }

  return newObject
}

The two generics O and A are making all the magic, especially the A generic: extends keyof O says "the second parameter must be an attribute from the object".

Then inside the function, TypeScript knows for sure that attr is an attribute from the object. I double-check with the attr in newObject if statement, in order to make sure at runtime everything is fine too. Just pure defensive programming.

The const newObject = { ...object } is here to make sure we don't modify the reference passed as arg, but return a new reference instead. It's some leftovers from my functional programming old days.

Now if we try the function :

const test = removeAttrFromObject({ a: 1, b: 2 }, 'a')
// returns as type `Omit<{a: 1, b: 2}, 'a'>` which equals `{a: 1}`

const test2 = removeAttrFromObject({ a: 1, b: 2 }, 'c') 
// TypeScript raise an error as `'c'` is not a key from the object passed

Upvotes: 3

Aleksey L.
Aleksey L.

Reputation: 37918

Typescript warns you about breaking the contract (the object won't have the required property anymore). One of the possible ways would be omitting the property when you cloning the object:

const myEvent = {
    coordinate: 1,
    foo: 'foo',
    bar: true
};

const { coordinate, ...eventData } = myEvent;
// eventData is of type { foo: string; bar: boolean; }

Playground


Operands for delete must be optional. When using the delete operator in strictNullChecks, the operand must be any, unknown, never, or be optional (in that it contains undefined in the type). Otherwise, use of the delete operator is an error.

Docs

Upvotes: 35

jperl
jperl

Reputation: 5112

What the error is telling you is that coordinate is not an optional property of that object (that is it can be undefined) and you are trying to delete it.

You could have deleted it if it was optional

coordinate?: FirebaseFirestore.Geopoint

It seems to have been introduced after version 4.0, you can read more about it here.

Upvotes: 0

Prabhjot
Prabhjot

Reputation: 39

You can delete if the property is optional

interface OptionalCoordinate {
   coordinate?
}

const eventData: OptionalCoordinate = {...myEvent}; // myEvent is an instance of my `Event` class
// ok to delete
delete eventData.coordinate; 

Upvotes: 2

Related Questions