Is there a workaround to Typescript's inclination to freeze objects in specific scopes while leaving others unaffected?

I am working with an interface:

interface Model {
  pre: Vertices,
  post: Vertices,
  m: Matrix,
  viewport: Vector,
  halfViewport: Vector,
  mouse: MouseState,
  selection: boolean
}

In my application, the state object is a specific instance of Model, with the selection property initialized to false. It's important to note that there is no readonly decorator present:

const state: Model = {
  ...
  selection : false
}

Due to performance considerations, Model values are updated directly since most properties are reference types. Consequently, there are various points in the code where these properties will be modified, sometimes deep within the call stack.

Interestingly, I have observed that it is perfectly permissible to modify the Model object's selection property within a function at the top scope:

function draw(state) { state.selection = !state.selection ... }

While I do not currently make this particular call in my code base, understanding where such modifications can occur is crucial. This becomes evident further down the stack, particularly when handling events in a React component, where an attempt is made to assign a value to selection:

function app (S: Model) : DOMElement<HTMLAttributes, Element> {
  const props = {
    ...
    onMouseDown: function (e: MouseEvent) : void {
      ...
      S.selection = false
    }
  }
  return React.DOM.div(props)
}

However, this assignment results in the following error message:

Uncaught TypeError: Cannot assign to read only property 'selection' of object '#<Object>'

Initially, I double-checked for the presence of a readonly keyword in the Model declaration, but found none. Upon inspecting the object in Chrome debugger, it appears that the object referenced by S is actually frozen (presumably due to `tsc` invoking `Object.freeze`). This behavior seems to be linked to TypeScript's excess property checking, where interfaces instances are scrutinized when assigned to variables or parameters. Is there a way around this limitation? It does seem inconsistent that mutations can occur in one scope but not another.

Answer №1

I am noticing that the object at point S appears to be frozen (similar to when `Object.freeze' is used in TypeScript. I wonder if this has something to do with the excess property checking in TS, where interface instances are verified for such issues when assigned to variables or parameters. Is there a way to work around this?

Contrary to what you might think, TypeScript does not generate code that calls Object.freeze. You can inspect the JavaScript output yourself and see for yourself. TypeScript's role is simply to strip away type annotations and transform ES6+ features into corresponding ES5 code, none of which involves applying freeze on arbitrary objects.

The object must have been frozen by some other means. It's possible that you are attempting to modify a property within a React component's state directly rather than using setState as intended. Without a full example, it's hard to pinpoint the exact issue.

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

What could be causing API requests to be directed to the incorrect URL in Vue.js 2?

I've been experimenting with learning Vue.js 2 and routing, and I'm puzzled by a specific issue. Whenever I navigate to routes other than the home ('/') route, the localhost URL is somehow added to the API calls. Here's an example ...

Expanding containers with flexbox to allow for flexibility in size

I need help with a page that contains 3 div elements, where 2 of them need to be resizable. These elements should be able to be moved left or right, and maximized or minimized. You can view the example on Stackblitz. The issue I'm facing is that som ...

Sending data through ajax to PHP on separate pages is a common practice

Here is where I choose my preferred option Company Name<br /> <select id="company" name="selected"> <option value="">Option A</option> <option value="">Option B</option> </select> When I click this, a mo ...

Using Three.js raycasting to determine the intersection point's coordinates

Hey there! I'm working on a project involving a plane and raycasting. What I'm trying to achieve is to obtain the coordinates of the intersection point on the plane. Any help would be appreciated, thanks! (Just to clarify, I changed the color as ...

The custom component is not updating the NgIf directive in HTML even though it receives a boolean variable

I am struggling with a custom component that includes an *ngIf in its view to handle a boolean variable, but for some reason the *ngIf directive is not working. Here is the code snippet: Component @Input('title') titleText; @Input('backButt ...

Display the size of the data array in VueJS once the data has been retrieved from the API

Using Vue JS, I have been attempting to retrieve data from an API. My goal is to determine the length of the array and then log it to the console using a method. However, every time I try to do this, the value logged is always "0" instead of the actual le ...

Issue with AngularJS: The view is not being updated after a nested http call

There is a specific scenario where I am required to make a call to the Github API in order to fetch the information of a particular user. Following that, I need to issue another call to retrieve the repositories belonging to that user: search(login: strin ...

Moving pictures using css3 transitions

Trying to create a straightforward image slider. Below is the provided JavaScript code: $(document).ready(function() { $('#slide1_images').on('click', 'img', function(){ $("#slide1_images").css("transform","translateX ...

I have attempted to create custom code for the built-in JavaScript function (toLocaleUpperCase). Can this be considered helpful or not?

Using this JavaScript code snippet, you can convert lowercase letters to uppercase without relying on built-in functions. This is a helpful concept to understand for interviews and coding challenges. //change lower case to upper case function Change ...

Tips for creating a cohesive group of HTML elements within an editable area

Imagine having a contenteditable area with some existing content: <div contenteditable="true"> <p>first paragraph</p> <p> <img width='63' src='https://developer.cdn.mozilla.net/media/img/mdn-logo-s ...

Obtain user input from a form and assign it to a variable in a jQuery AJAX

How can I pass the value of an HTML Input Form to a jQuery AJAX call's URL as `amt` in `url: "http://localhost:8080/orderNo?amount=" + amt,`? The input value logs to the console when calling getAmtValue(), but I'm struggling to access the `amt` ...

The Word Document is unable to locate the module or its associated type declarations

Encountering an issue while attempting to import a file from the src/assets/documents directory. https://i.sstatic.net/Gxq05.png Currently working on a React Project using Typescript. The goal is to import a file and use its value within an anchor tag fo ...

Error: [*] is inaccessible prior to initialization. Implementing nested object validation using Class-validator in NestJs

I'm really struggling to grasp what's happening here and where I might be going wrong. I've searched through similar threads, but none seem to address my specific issue (most discussions revolve around validating typed Arrays). Let me prese ...

Changing the position of the scroll bar in a side navigation bar using JS/jQuery

On my website, there is a side navigation bar with the following CSS style: .scroll-box { overflow: hidden; width: 128px; } .filler { height: 256px; overflow-y: auto; } .selector { background-color: #369; padding: 8px 4px; text-align: cent ...

"Error encountered when making a request to Google API using Ember.js, response remains

Trying to fetch place suggestions from Google API using Ember js. Below is the code snippet for the service module: fetch(){ let url=`https://maps.googleapis.com/maps/api/place/autocomplete/json?input=IL&types=geocode&key=API_KEY` return Ember.RSV ...

Error thrown: Openerp 7.0 fails to read the prototype property of null due to a TypeError

Using Openerp (Version 7.0-20140429-231256) has been smooth sailing until I encountered a sudden error one day that left me stumped. Despite my efforts, I couldn't find any solutions to resolve this exception. OpenERP Client Error Uncaught TypeError: ...

AngularJS expression comments allow developers to add explanatory notes or reminders

When working with HTML tags that contain ng-clicks and ng-ifs in Angular, I often make function calls and pass in parameters, including literals such as true or false. However, I've noticed that it's difficult to add comments explaining what thes ...

Tips on sending data with a unique identifier to the backend through a route parameter

Can anyone help me figure out how to send a message to a specific backend route parameter while passing the current ID? I'm not sure how to inform the system about this ID. Here's the Vuex action: postMessage({commit}, payload, id) { axios.pos ...

Arranging Objects by Alphabetical Order in Typescript

I am struggling with sorting a list of objects by a string property. The property values are in the format D1, D2 ... D10 ... DXX, always starting with a D followed by a number. However, when I attempt to sort the array using the following code snippet, it ...

How to apply props conditionally in VueJS?

I have a component called blogPost (Component A) that is imported in another component named B. When a button in Component B is clicked, Component A opens in a modal. There are two different use cases for this scenario. 1. One case requires passing 2 prop ...