This error, TS2790: The 'delete' operand must be optional, means you’re trying to delete a property from an object that TypeScript’s type checker has determined cannot be deleted. This usually happens when you’re working with types that declare properties as readonly or when you’re attempting to delete a property that’s part of a specific, non-configurable object structure.
Here are the common culprits and how to fix them:
1. Deleting a readonly Property
This is the most frequent cause. You’ve defined an interface or type where a property is marked with readonly, and then you try to remove it.
Diagnosis: Look at the type definition for the object you’re trying to delete from. If the property in question is marked readonly, that’s your problem.
interface MyConfig {
readonly setting: string;
}
const config: MyConfig = { setting: "enabled" };
delete config.setting; // TS2790
Fix: You cannot directly delete a readonly property. The readonly keyword explicitly tells TypeScript that this property should not be modified or removed after initialization.
If you need to remove the property, you must create a new object without that property.
interface MyConfig {
readonly setting: string;
optionalSetting?: string; // Add an optional property if needed
}
const config: MyConfig = { setting: "enabled" };
// Option 1: Create a new object excluding the readonly property
const { setting, ...restOfConfig } = config; // Destructure to exclude 'setting'
const newConfig = restOfConfig; // newConfig is now {}
// Option 2: If you intended to remove an optional property, ensure it's optional
// If config had an optional property, e.g., optionalSetting, you could do:
// delete config.optionalSetting; // This would be valid if optionalSetting was not readonly
Why it works: TypeScript’s readonly modifier is a compile-time guarantee. It prevents accidental modification. By creating a new object, you’re not violating the readonly constraint on the original object; you’re simply building a new data structure.
2. Deleting Properties from Primitive Wrappers or Built-in Objects
You might encounter this when trying to delete properties from JavaScript’s built-in objects or their wrappers, which often have non-configurable properties.
Diagnosis: Check if the object you’re operating on is a primitive type wrapper (like String, Number, Boolean) or a standard built-in object (like Math, Date, Object.prototype).
const myString = new String("hello");
// Attempting to delete a property from a String object wrapper
delete myString.length; // TS2790
Fix: You generally cannot and should not attempt to delete properties from these built-in types. Their internal structure is managed by the JavaScript engine.
If you’re trying to modify a string, you should use string methods that return new strings.
const myString = new String("hello");
// Instead of deleting, create a new string or use string methods
const newString = myString.substring(0, 3); // "hel"
Why it works: Built-in JavaScript objects often have properties that are non-configurable by design. The delete operator is designed to work on properties of ordinary objects. Trying to delete a non-configurable property results in false being returned and no change to the object, but TypeScript flags this as a potential error.
3. Deleting Properties from Objects Created with Object.freeze()
Object.freeze() makes an object’s properties immutable and non-configurable.
Diagnosis: Check if the object was previously frozen using Object.freeze().
const frozenObject = Object.freeze({ id: 123, name: "Test" });
delete frozenObject.name; // TS2790
Fix: Similar to readonly properties, you cannot modify or delete properties of a frozen object. You must create a new object if you need a version without certain properties.
const frozenObject = Object.freeze({ id: 123, name: "Test" });
// Create a new object excluding the property
const { name, ...rest } = frozenObject;
const newObject = rest; // newObject will be { id: 123 }
Why it works: Object.freeze() is a more aggressive form of immutability than readonly. It prevents any changes, including adding, deleting, or modifying properties. Creating a new object bypasses this restriction by operating on a fresh, unfrozen entity.
4. Deleting Properties from Objects Created with Object.seal()
Object.seal() prevents adding or deleting properties but allows existing properties to be modified.
Diagnosis: Check if the object was sealed using Object.seal().
const sealedObject = Object.seal({ value: 10 });
delete sealedObject.value; // TS2790
Fix: You cannot delete properties from a sealed object. You’ll need to create a new object.
const sealedObject = Object.seal({ value: 10 });
// Create a new object
const { value, ...rest } = sealedObject;
const newObject = rest; // newObject will be {}
Why it works: Object.seal() ensures that the number of properties on an object remains constant. While you can change the values of existing properties, you cannot remove them. Again, the solution is to construct a new object.
5. Deleting Properties of arguments or this in Certain Contexts
In some specific JavaScript environments or when dealing with certain this bindings, arguments or properties of this might behave in ways that make them undeletable.
Diagnosis: This is less common and harder to diagnose directly via TypeScript errors unless the type of arguments or this is explicitly constrained. It often manifests as a runtime error or unexpected behavior rather than a compile-time TS2790. However, if you do see TS2790 here, it means the property you’re targeting on arguments or this is not subject to deletion.
Fix: Avoid deleting properties from arguments or this. If you need to manipulate the arguments or properties of this, create copies or new objects.
function processArgs(...args: any[]) {
// Avoid deleting from 'arguments' if it were directly accessible and non-deletable
// Instead, work with the 'args' array which is standard ES6
const newArgs = args.filter(arg => arg !== undefined); // Example: filter out undefined
}
class MyClass {
private internalValue: number;
constructor() {
this.internalValue = 5;
}
reset() {
// Instead of trying to delete and reassign, just reassign
this.internalValue = 0;
}
}
Why it works: arguments is a special object in JavaScript, and its properties (especially indexed ones) can have specific behaviors. this refers to the current execution context, and its properties might be dynamically created or have special characteristics depending on how the object is constructed or functions are called. Manipulating them via delete is often discouraged and can lead to unexpected results or errors.
6. Non-Standard Object Properties (Rare)
In extremely rare cases, you might be dealing with objects where properties are defined in a way that makes them non-configurable. This is usually not something you’d encounter in typical application code but could arise from libraries or specific JavaScript engine behaviors.
Diagnosis: This is very hard to diagnose without deep introspection. If you’ve exhausted all other options and the property still cannot be deleted, it’s likely non-configurable.
Fix: Treat the property as if it were readonly. Create a new object without the property.
// Assume 'unusualObject.someProp' is non-configurable
const { someProp, ...rest } = unusualObject;
const newObject = rest;
Why it works: The underlying JavaScript engine has marked the property as non-configurable, meaning its attributes (like writability or deletability) cannot be changed. The only way to achieve a similar outcome to deletion is to exclude it from a new, derived object.
After addressing the TS2790 error, the next problem you might encounter is related to type compatibility if you’ve created new objects. For instance, if you remove a required property to make an object optional, you might then run into TS2322: Type '...' is not assignable to type '...' if the receiving type still expects the original, complete structure.