Implementing Read-Only Properties in Interfaces and/or Classes

I am currently working on a class that acts as a Model and I want to ensure that the data within it is read-only. While this may seem straightforward at first, things get more complicated when dealing with nested data structures. Let me provide an example from my code to illustrate this further:

export class MyModel {
  readonly One: IOne;
  readonly Two: ITwo;
  readonly Three: IThree;

  constructor() {
    this.One.A = "foo";
    this.One.B = "bar";
    this.Two.C = "totally";
    this.Two.D = "utterly";
    this.Three.E = "completely";
    this.Three.F = "messed up"
  }
}

interface IOne {
  A: string;
  B: string;
}

interface ITwo {
  C: string;
  D: string;
}

interface IThree {
  E: string;
  F: string;
}

Now, in a component:

import { MyModel } from './my.model';

export MyComponent {
  
  dataB:string;
  dataD:string;
  dataE:string;

  constructor(
    private mymodel: MyModel
  ){
    this.dataB = mymodel.One.B; // works as expected
    mymodel.Two = ""; // causes error due to readonly property, which is expected
    mymodel.Three.F = "something else"; // works, but I also want this to be read-only
  }

}

The goal here is to organize data where it belongs while benefiting from IDE suggestions like auto-completion when typing 'mymodel.One.B'. However, I also need the properties from the Interfaces to be read-only.

If I mark the Interfaces as readonly, I naturally encounter errors in MyModel since I cannot assign values to read-only properties. To work around this, I attempted to create classes implementing these Interfaces with readonly properties and then use those classes instead of the interfaces. This approach did not prevent assigning values in MyComponent though. Here's an example:

export class MyModel {
  readonly One: One;
  readonly Two: Two;
  readonly Three: Three;

  constructor() {}
}

class One implements IOne {
  readonly A = "foo";
  readonly B = "bar";
}

class Two implements ITwo {
  readonly C = "totally";
  readonly D = "utterly";
}

class Three implements IThree {
  readonly E = "completely";
  readonly F = "messed up";
}

interface IOne {
  A: string;
  B: string;
}

interface ITwo {
  C: string;
  D: string;
}

interface IThree {
  E: string;
  F: string;
}

Despite these changes, the outcome remains the same in MyComponent. How can I enforce read-only for properties A, B, C, etc.?

Answer №1

After some trial and error, I finally figured out the correct approach to get this working smoothly.

It dawned on me that the current structure of MyModel was causing trouble as soon as MyComponent tried to instantiate it due to the undefined value of mymodel.A. The breakthrough came when I realized that setting values outside of the constructor was the key, ultimately resolving my initial issue:

export class MyModel {
  readonly One: IOne = {
    A: "foo",
    B: "bar"
  }

  constructor(){}
}

interface IOne {
  readonly A: string,
  readonly B: string
}

By making this adjustment, I was able to trigger the necessary error message when attempting to assign a value to mymodel.One.A within MyComponent.

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

Apollo useQuery enables risky array destructuring of a tuple element containing any value

Currently, I am incorporating TypeScript into my project and have a GraphQL query definition that utilizes Apollo's useQuery. According to the documentation, the call should be typed, however, I am encountering an ESLint error regarding data being ass ...

Angular leverages the use of proprietary libraries

I recently created a library and decided to share it by publishing it on a repository. The idea was to be able to easily incorporate it into my other projects using npm. However, upon launching my project, I encountered the following error: ERROR in Canno ...

Issue encountered when attempting to access disk JSON data: 404 error code detected

I am attempting to retrieve JSON data from the disk using a service: import { Product } from './../models/Product'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { HttpClient } from &apo ...

Having issues with an Angular reactive form that includes a custom form-level validator and the 'blur' updateOn option?

Having issues combining the following: angular reactive form custom validator at form level (cross-field validator) usage of the 'updateOn' option set to 'blur' A demonstration of the problem can be found in this simple stackblitz: h ...

Unable to instantiate object while defining a custom copy constructor

Adding a copy constructor has caused issues with this code that previously worked. #include <iostream> #include <string.h> using namespace std; class Laptop { public: string brand; string model; int ram; i ...

Tips for aligning text in a stylish way on an Angular Material Button

My angular material button has been customized with increased size and the text is currently offset. Here is the code: <a mat-raised-button class="buttons-class" color="accent">Hello!</a> To increase the size, the following ...

"Implementing Two-Way SSL with Angular 2 and BrowserSync

Currently, I am working on an Angular2 application that requires two-way SSL authentication. This means that the browser needs to present a valid (PFX) certificate in order to access the application. For deployment, I am using lite-server (which utilizes B ...

The view fails to update when the object is modified

Within the acceptRequest function in child.component, the commissioner.requestAccepted property is set to false, and then the updated commissioner object is returned. Ideally, I want the button to be automatically removed from the view once the object is ...

Exploring the Magic of Class Variable Destructuring in React

Is there a simpler method to break down a prop object and assign them to variables of the same name in the class? I am familiar with ({ first: this.first, second: this.second, } = props) however, it can get complicated when dealing with numerous variable ...

Angular 2 Material Primary Focus

Struggling with altering the foreground color in Angular 2 material? Specifically, the text in the toolbar displays as black. I attempted to adjust it using the following styles: @import '~@angular/material/theming'; $primary: mat-palette($mat- ...

What is the preferred method for validating an Angular form - ng-model or form input name?

When it comes to validating an input field and providing feedback, there are two methods that I have noticed: <form name="myform" ng-submit="myform && myFunc()"> <input name="foo" ng-model="foo" ...

Convert YAML to an array of objects instead of using named objects in npm parsing

Currently, I am utilizing npm's YAML parser to convert YAML into an object. However, instead of getting an array, I am receiving a group of named objects. This issue arises from the absence of dashes preceding the objects. How can I transform this gr ...

Tips for obtaining the most recent HTML element in Angular

I was able to include HTML content in an Angular (7) UI using the DomSanitizer this.sanitizer.bypassSecurityTrustHtml("htmlstr") Once the content is sanitized and displayed in the HTML view, users have the ability to modify the values as desired ...

Obtain text output from an Observable

After retrieving a String from the backend: String value = "{I am here}"; In my service method: getValue(): Observable<String> { return this.http.get<String>(this.myURL); } In my component, I am subscribing to this method: String myM ...

Debug a Typescript-enabled Koa application remotely from a Docker container using Webstorm

Issue: Currently facing challenges while setting up a new NodeJS Project using KoaJS, Typescript, and Docker. The initial setup went as planned, but encountering some difficulties with remote debugging - or at least it seems so from my perspective. When s ...

What steps can I take to make my animation work in the opposite direction as well?

I'm currently working with an angular slider that is set to TRUE/OPEN by default. The issue I am facing is that while I am able to slide it using angular animations in one direction, I am unable to see the transition when sliding it back. Any assistan ...

Achieving successful integration of SignalR with Angular 5 within the environment of dot net framework version 4.6.1

Currently, I am in the process of setting up SignalR using the Dot Net Core Angular template found in Visual Studio Professional. Due to having a significant amount of legacy code to maintain, I have opted for .NET Framework 4.6.1. https://i.sstatic.net/j ...

Switching a div class in Angular 6 with a button click: A step-by-step guide

In this scenario, I have a div with the class name old. There is also a button that, when clicked, should toggle the div's class name between old and new. I am looking for a solution using Angular 6. Below is the code snippet: I am relatively new to ...

Typescript does not process and compile files located within a specified directory

Recently, I embarked on a small TypeScript project and took the time to create the tsconfig.json configuration file. { "compilerOptions": { "target": "es5", "module": "commonjs", "sourceMap": true }, "files": [ "./typings/index.d.ts" ...

The issue I'm facing with the mongoose schema.method is that the TypeScript error TS2339 is showing up, stating that the property 'myMethod' does not exist on type 'Model<MyModelI>'

I am looking to integrate mongoose with TypeScript and also want to enhance Model functionality by adding a new method. However, when I try to transpile the file using tsc, I encounter the following error: spec/db/models/match/matchModelSpec.ts(47,36): e ...