You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Readonly indexer and constructor usage: question #6781
I don't think this is a bug. An index signature introduces no new properties and the constructor rule applies to properties. We could consider extending the rule to index signatures, but I'm not sure that's particularly useful. Is there are scenario that doesn't work with the existing rules?
Note that the following does work because this.x and this["x"] are just different ways of writing the same thing:
classA{readonlyx: string;readonly[x: string]: string;constructor(){this.x="s";// Okthis["x"]="s";// Ok, same as this.xthis["a"]="s";// Error, no declaration of a in this class}}
It seems like any case for disallowing this also applies to non-reaonly signatures. If you had a normal index signature, we'd let you write this["a"] = "s" in the constructor, of course, so the point that the a property is not declared is a red herring.
Now we've added readonly for both index signatures and properties and said that readonly doesn't apply in the constructor... but only for properties? That just seems weird.
Anton Lobov (@zhuravlikjb) can you share a repro with more real-world names (maybe outline the broad usage of the class)? We talked about this for a while and couldn't agree on what the developer intent of a read-only index signature on a class is. Understanding how you're using this would be helpful.
Ryan Cavanaugh (@RyanCavanaugh) Unfortunately, I develop a tool for TypeScript support, but written not in TypeScript, so this example is not a real-world thing, but just a test case, a theoretical question. If there are no real-user requests for this, you can freely close the issue.
I just ran into this problem when I implemented a dictionary like class, the uscase is a table with items which contain an indexed value for each table column.
A workaraound-solution is to use the object.assign function in the constructor, but I think it would be better to have a consistent behavior of the compiler to allow indexed value assignments in the constructor.
My use case is that I implement a lot of immutable structures. I don't allow imperative mutation of key-value pairs, and instead construct new instances of things with the desired changes. This means that read-only indexers are a must, but that the set of keys being assigned is only known at runtime, and established within the constructor. Certainly I can work around this by having my properties be held internally and accessed indirectly via a readonly indexer, but then I'm changing the runtime characteristics of my implementation not because it's best for the application's architecture, but because TypeScript won't play ball. In this case my workaround involves casting to any first, but that's kind of hacky and prone to breakage when refactoring.
this[i] = value obviously doesn't work with the current rules, and I don't understand the reasoning:
An index signature introduces no new properties and the constructor rule applies to properties.
An index signature defines unspecific extra properties, and the constructor is the place to set them if they're readonly, because the object is created in the constructor so it's local mutation.
Reacted by Tobias Haimerl, neurozero, Şafak Gür, Tavian Barnes and Joshua Wise
Activity
RyanCavanaugh commentedon Feb 1, 2016
I believe indexed assignments should be allowed in the constructor
zhuravlikjb commentedon Feb 1, 2016
It's also interesting how it should behave in case of inheritance.
ahejlsberg commentedon Feb 1, 2016
I don't think this is a bug. An index signature introduces no new properties and the constructor rule applies to properties. We could consider extending the rule to index signatures, but I'm not sure that's particularly useful. Is there are scenario that doesn't work with the existing rules?
Note that the following does work because
this.xandthis["x"]are just different ways of writing the same thing:RyanCavanaugh commentedon Feb 1, 2016
It seems like any case for disallowing this also applies to non-
reaonlysignatures. If you had a normal index signature, we'd let you writethis["a"] = "s"in the constructor, of course, so the point that theaproperty is not declared is a red herring.Now we've added
readonlyfor both index signatures and properties and said thatreadonlydoesn't apply in the constructor... but only for properties? That just seems weird.RyanCavanaugh commentedon May 9, 2016
Anton Lobov (@zhuravlikjb) can you share a repro with more real-world names (maybe outline the broad usage of the class)? We talked about this for a while and couldn't agree on what the developer intent of a read-only index signature on a class is. Understanding how you're using this would be helpful.
zhuravlikjb commentedon May 10, 2016
Ryan Cavanaugh (@RyanCavanaugh) Unfortunately, I develop a tool for TypeScript support, but written not in TypeScript, so this example is not a real-world thing, but just a test case, a theoretical question. If there are no real-user requests for this, you can freely close the issue.
RyanCavanaugh commentedon May 10, 2016
Anton Lobov (@zhuravlikjb) thanks for the info. I'll leave this one awaiting feedback then.
kaoDev commentedon Jan 31, 2017
I just ran into this problem when I implemented a dictionary like class, the uscase is a table with items which contain an indexed value for each table column.
A workaraound-solution is to use the object.assign function in the constructor, but I think it would be better to have a consistent behavior of the compiler to allow indexed value assignments in the constructor.
This stackoverflow discussion is linked to this issue:
http://stackoverflow.com/questions/41953540/typescript-dictionary-with-readonly-keys/41953915#41953915
axefrog commentedon Aug 22, 2017
My use case is that I implement a lot of immutable structures. I don't allow imperative mutation of key-value pairs, and instead construct new instances of things with the desired changes. This means that read-only indexers are a must, but that the set of keys being assigned is only known at runtime, and established within the constructor. Certainly I can work around this by having my properties be held internally and accessed indirectly via a readonly indexer, but then I'm changing the runtime characteristics of my implementation not because it's best for the application's architecture, but because TypeScript won't play ball. In this case my workaround involves casting to
anyfirst, but that's kind of hacky and prone to breakage when refactoring.slikts commentedon Jul 19, 2018
My use case is constructing a frozen array-like:
this[i] = valueobviously doesn't work with the current rules, and I don't understand the reasoning:An index signature defines unspecific extra properties, and the constructor is the place to set them if they're
readonly, because the object is created in the constructor so it's local mutation.tavianator commentedon Aug 16, 2019
Is there a workaround for this for numeric indices, other than using
Object.defineProperty(this, i, { value: value })?slikts commentedon Aug 16, 2019
I'd do this before the assignment:
// @ts-ignore: https://github.com/microsoft/TypeScript/issues/6781The link being there to document why it's done.
JoshuaWise commentedon Aug 25, 2019
Like Reinis Ivanovs (@slikts), I also need this for a frozen array-like class. It was very surprising to me that this doesn't work.