TypeScript icon indicating copy to clipboard operation
TypeScript copied to clipboard

2.4: Readonly<Map<k,v>> vs. ReadonlyMap<k,v>

Open BurtHarris opened this issue 7 years ago • 9 comments

TypeScript Version: 2.4.1

Code

function GenMap() : ReadonlyMap<string, number> {
    const theMap = new Map<string, number>();
    theMap.set("one", 1);
    theMap.set("two", 2);
    return Object.freeze(theMap);
}

Expected behavior: Compiles without error in tsc@<2.4.0

Actual behavior:

TryX.ts(5,5): error TS2322: Type 'Readonly<Map<string, number>>' is not assignable to type 'ReadonlyMap<s
tring, number>'.
  Property '[Symbol.iterator]' is missing in type 'Readonly<Map<string, number>>'.

BurtHarris avatar Jun 29 '17 22:06 BurtHarris

You cannot make a Map read only with Object.freeze. Sounds like this is working as intended to me.

sylvanaar avatar Jun 30 '17 08:06 sylvanaar

That's surprising. @sylvanaar can you provide a reference supporting this?

No matter what the runtime-behavior, Its is a change in compile-time behavior from TypeScript 2.3.x.,

BurtHarris avatar Jun 30 '17 17:06 BurtHarris

https://stackoverflow.com/questions/35747325/is-there-a-way-to-freeze-a-es6-map

Also, you can test it yourself: http://jsbin.com/zorumaceyu/edit?js,console

I think they gave a reasonable type for a Map returned from Object.freeze in the current release Readonly<Map<T>>

#12377 they added support for ReadOnlyArray, buit shouldn't have.

sylvanaar avatar Jun 30 '17 20:06 sylvanaar

We need new overloads to freeze,:

    freeze<K,V>(a: Map<K,V>): ReadonlyMap<K,V>;

and set as well since we are at it:

    freeze<T>(a: Set<T>): ReadonlySet<T>;

mhegazy avatar Aug 28 '17 20:08 mhegazy

PRs welcomed

mhegazy avatar Aug 28 '17 20:08 mhegazy

@mhegazy , as @sylvanaar 's comment/link shows, calling Object.freeze on a map doesn't actually stop new keys being added with .set(). Do the suggested overloads still make sense in this case?

NaridaL avatar Sep 18 '17 19:09 NaridaL

Readonly<Map<_, _>> is not the same as ReadonlyMap<_, _>. I think the latter is a subset of the former, so the best solution would be to make Readonly<Map<_, _>> assignable to ReadonlyMap<_, _>.

ThomasdenH avatar Jan 31 '19 13:01 ThomasdenH

This issue is caused by the fact that keyof does not include well known symbols (in this case Symbol.iterator). This problem has been already reported in issue #24622 and will be resolved with #24738.

marcin-serwin avatar Jan 14 '20 19:01 marcin-serwin

Interestingly ReadonlyArray<T> and Readonly<Array<T> are assignable to each other. I wish that Readonly<Foo> would alias to ReadonlyFoo as long as it's in scope. Ideally, we should also check that Foo is assignable to ReadonlyFoo.

kevinbarabash avatar Nov 03 '22 04:11 kevinbarabash