Decorating a class with a decorator does not effectively seal the class

I'm attempting to apply a decorator to seal my class object, but it seems like it's not working. Even after initializing the class, I am able to delete a property or add another one to the class. Here is the code snippet:

function sealed(constructor: Function) {
  Object.seal(constructor);
  Object.seal(constructor.prototype);
}

@sealed
class BugReport {
  type = 'report';
  title: string;

  constructor(t: string) {
    this.title = t;
  }
}

const bug = new BugReport('but');

delete bug.title;
delete bug.type;

console.log(bug); // BugReport {}

However, when I tried sealing a pure object, everything worked as expected. Here is the code snippet for that:

const obj = {
  name: 'Jack',
};

Object.seal(obj);

delete obj.name;

console.log(obj); // will throw an error: Cannot delete property 'name'

This issue arises in the tsconfig.json file as well.

{
  "compilerOptions": {
    // `target` and `lib` match @tsconfig/bases for node12, since that's the oldest node LTS, so it's the oldest node we support
    "target": "es2019",
    "lib": ["es2019", "es2020.promise", "es2020.bigint", "es2020.string", "dom"],
    "rootDir": "src",
    "outDir": "dist",
    "module": "commonjs",
    "moduleResolution": "node",
    "strict": true,
    "declaration": true,
    "sourceMap": true,
    "inlineSources": true,
    "types": ["node"],
    "stripInternal": true,
    "incremental": true,
    "skipLibCheck": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "strictPropertyInitialization": false
  },
  "ts-node": {
    "swc": true
  },
  "include": ["src/**/*"],
  "typedocOptions": {
    "entryPoints": ["./src/index.ts"],
    "readme": "none",
    "out": "website/static/api",
    "excludeTags": ["allof"],
    "categorizeByGroup": false,
    "categoryOrder": ["Basic", "REPL", "Transpiler", "ESM Loader", "Other"],
    "defaultCategory": "Other"
  }
}

Why is the decorator function unable to manipulate the class at all?

Appreciate any assistance provided.

Answer №1

Object.seal is explained in detail on the MDN page:

The Object.seal() method seals an object, preventing new properties from being added to it and marking all existing properties as non-configurable.

You are sealing not only the class constructor itself but also its prototype.

If you try to add a property to the prototype like this:

BugReport.prototype.modified = 42;

An error will occur because the prototype has been sealed. Similarly, attempting to modify the constructor will also throw an error:

BugReport.modified = 42;

It's important to note that the properties on the class do not belong to the prototype either:

console.log(BugReport.prototype); // {}

To achieve the desired behavior, make sure to seal the instance in the class constructor:

constructor(t: string) {
    this.title = t;

    Object.seal(this); // seal THIS instance
}

Now, any attempt to modify the instance will result in errors.

Feel free to experiment with this concept in the playground.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Different ways to categorize elements of Timeline using typescript

I have some code that generates a timeline view of different stages and their corresponding steps based on an array of stages. Each stage includes its name, step, and status. My goal is to organize these stages by name and then display the steps grouped un ...

Firing a function in Angular2 whenever an observable property undergoes a change

Utilizing a workingData service that stores crucial data across my application, it provides an observable to the Mock workingData object. @Injectable() export class WorkingDataService { getWorkingData(): Observable<WorkingData> { return Observ ...

What is the method for retrieving properties from a generic in typescript?

In my code snippet, I am dealing with a generic type variable called data and I am looking for a way to access the values of its properties. The method hasOwnProperty isn't effective in this case due to the generic nature of the data. const data: T = ...

Include a new module in the declarations NgModule utilizing ts-morph

Currently, I am utilizing the ts-morph library and my objective is to add a new component to the declarations: This is my initial setup: @NgModule({ declarations: [], imports: [], providers: [], }) Here is what I am aiming for: @NgModule({ declarations: [ ...

Guide to defining font style in vanilla-extract/CSS

I'm trying to import a fontFace using vanilla-extract/css but I'm having trouble figuring out how to do it. The code provided in the documentation is as follows: import { fontFace, style } from '@vanilla-extract/css'; const myFont = fo ...

Unable to locate a declaration file for the 'mymodule' module

After attempting to import my test module by installing it with npm i github.com/.../..., the code is functioning properly. However, when I opened it in VSCode, an error message popped up: Could not find a declaration file for module 'estrajs'. & ...

Error: XYZ has already been declared in a higher scope in Typescript setInterval

I've come across an interesting issue where I'm creating a handler function and trying to set the current ref to the state's value plus 1: const useTimer = () => { const [seconds, setSeconds] = useState(0); const counterRef = useRef(n ...

I am experiencing slow load times for my Angular 2 app when first-time users access it, and I am seeking assistance in optimizing its speed

Below, you'll find a snippet from my app.ts file. I'm currently working with angular2, firebase, and typescript. I'm curious if the sluggish performance is due to the abundance of routes and injected files? The application functions smoot ...

I encountered a typescript error while trying to export my Class component within a Higher Order Component (HOC)

I'm encountering a TypeScript error with my HomePage Class Component. Below is the code snippet: import * as React from "react"; import { Dispatch, AnyAction } from 'redux'; import { connect } from 'react-redux&apos ...

An error occurred due to attempting to access properties of null while trying to read 'useMemo' in a Next.js TypeScript application

Currently engaged in a Next.js 13 project with TypeScript, utilizing the useDrag hook. No errors are being flagged in my Visual Studio Code editor; however, upon attempting to render the page, an error message surfaces. The issue points to a problem with t ...

The error message "Property '$store' is not defined on type 'ComponentPublicInstance' when using Vuex 4 with TypeScript" indicates that the property '$store' is not recognized

I'm currently working on a project that involves using TypeScript and Vue with Vuex. I've encountered an error in VSCode that says: Property '$store' does not exist on type 'ComponentPublicInstance<{}, {}, {}, { errors(): any; } ...

Can you explain the significance of syntax in sample code (typescript, react)?

const sampleFunction: (inputString: string) => string = inputString => { return inputString.split(""); } I'm a bit confused about the code below and would appreciate some clarification. I understand that only "string" as a type is accepted, b ...

Changing the global type in TypeScript

Currently, I am incorporating two third-party TypeScript libraries into my project. Interestingly, both of these libraries expose a global variable with the same name through the Window interface. However, they offer different methods for interacting with ...

Conditional void parameter type in Typescript

Attempting to create a custom Error class that can handle different data based on the error code seemed like a complex task for TypeScript. However, surprisingly, it was successful: const enum ERROR_CODES { E_AUTHORIZATION = 'Authorization error&ap ...

What is the best way to define several mapped types in TypeScript?

Imagine you have the following lines of TypeScript code: type fruit = "apple" | "banana" | "pear" type color = "red" | "yellow" | "green" You want to define a type that includes a numeric propert ...

How to retrieve a component's property within an Angular2 provider?

As a beginner in OOP, I am currently experimenting with Ionic 2, Angular 2, and TypeScript. In my home.html file, I have an input field connected to the username property in home.ts as shown below: export class HomePage { public username: string; public n ...

Angular2's ErrorHandler can cause code to malfunction when an error occurs

import { Injectable, ErrorHandler, Inject, Injector } from '@angular/core'; import { MessengerService } from '../services'; import { MessageTypeEnum } from '../../shared'; @Injectable() export class AppErrorHandler extends Er ...

Angular Error Handler - Extracting component context information from errors

In the event of a TypeScript error, I am looking to send all of the component's attribute values to a REST API. It would greatly benefit me if I could access the component's context (this) in order to retrieve the values of all attributes within ...

Unlock the Power of Angular: Leveraging ViewEncapsulation.Native to Access HTML Elements

I am encountering an issue where I am receiving an error when trying to access an HTML element by ID. The problem arises when I attempt to access the classList upon a user clicking a button to apply a different style class to the element. The class list an ...

The CosmosClient's read() method will only return an object if both the ID and partition key value are provided

After setting up a CosmosDB instance and inserting a test object into the container products, with the partition key set to /price, I encountered an issue. The item added had the following properties: { "id": "1234", "name": "A DB product", "p ...