Skip to content

Support readonly type operator to allow correct definition of Object.freeze #10725

Closed
@spiffytech

Description

@spiffytech

TypeScript Version: 2.0@RC

Code

// Current definition of `Object.freeze`:
// freeze<T>(o: T): T;

const o = Object.freeze({a: 1});
o.a = 2;  // Should throw type error
console.log(o);  // {a: 1}

Expected behavior:
Frozen object has readonly properties
Actual behavior:
Type system allows me to write to o's properties

Activity

mhegazy

mhegazy commented on Sep 6, 2016

@mhegazy
Contributor

There is no readonly type operator; i.e. freeze<T>(o: T): readonly T;. so there is no way to do this at the time being.

We have discussed adding a readonly type operator that would recursively mark all properties as readonly.

mhegazy

mhegazy commented on Sep 6, 2016

@mhegazy
Contributor

updating the title.

changed the title [-]Object.freeze declaration should mark fields readonly[/-] [+]Support `readonly` type operator to allow correct definition of `Object.freeze`[/+] on Sep 6, 2016
deregtd

deregtd commented on Sep 14, 2016

@deregtd

In our huge Typescript app, we're using a data storage mechanism that keeps complicated class-based types inside data stores. The rest of the app consumes these objects from the stores, but there's always a risk of developers trying to modify the objects that come out of the stores, which ruins delta checking across the app. We could use object.freeze(), but that plays havoc with JIT.

Instead, we maintain duplicate deep readonly versions of all of our model objects. The stores distribute readonly versions, and if anyone actually needs to update them, they first clone the readonly object back into an impl object, modify it, and then shove it back in the store. The store takes it in and stores it as a readonly version.

The general data access pattern works fantastically. There's no javascript overhead from object.freeze(), and our engineers are unable to do terrible things with our data models (outside of casting, of course...) The big issue is just that we have a ton of these deep readonly models that we're manually maintaining, and also having to have comments to maintain which methods are readonly-accessible. We're used to just using "const" in C++ to solve this problem, both on the accessors (from stores) and for the readonly-safe methods in a class, so this is definitely a step backward, and has introduced some engineer errors by not keeping the two versions in sync.

At least we have readonly at all, it was a huge boon to us to get that. :) I'm just hoping for a true deep "const"-style readonly someday.

asfernandes

asfernandes commented on Feb 5, 2017

@asfernandes

Should not this be closed after #12114 and Readonly<T>?

deregtd

deregtd commented on Feb 5, 2017

@deregtd

It depends if there's any hope of a const-style. We haven't bothered using ReadOnly<> because, to be frank, it's worthless to us. We need deep readonly, so we have just created basically deep readonly types as copies of normal types. I don't really understand how shallow readonly helps, unless all of your interfaces are just a list of primitives, without any deep classes on them.

asfernandes

asfernandes commented on Feb 5, 2017

@asfernandes

@deregtd I agree with you on worthless of shallow Readonly. But Object.freeze is shallow too and is already changed per this issue.

deregtd

deregtd commented on Feb 5, 2017

@deregtd

Fair enough. Should I just open a new one asking for true const?

asfernandes

asfernandes commented on Feb 5, 2017

@asfernandes

Isn't what #11535 (referenced in this issue) is already asking for?

deregtd

deregtd commented on Feb 5, 2017

@deregtd

Kinda. He's asking to mark interfaces as full readonly. I want to have a basic set of interfaces, and then be able to mark certain usages of them as const, and have it be deep C++-style const, without having to make a complete second copy of all of them. All the attached bugs seem to basically be solved by the partial types business.

asfernandes

asfernandes commented on Feb 5, 2017

@asfernandes

C++-style const does not do what you say when using references and pointers (and that's how js/ts works), for example:

class Parent
{
public:
    /*const*/ Child* child;
};

const Parent* parent = ...;
parent->child->iCanMutateThis = true;

I think the idea should not be about have a const making a variable readonly, but a form of deeply apply something like Readonly<>. See my #13214 and the referenced issue #12424. Unfortunately, seems #12424 is more about theory than something practical.

60 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    In DiscussionNot yet reached consensusSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @spiffytech@pelotom@genXdev@ikokostya@lukescott

        Issue actions

          Support `readonly` type operator to allow correct definition of `Object.freeze` · Issue #10725 · microsoft/TypeScript