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<> does not work on tuple types in 3.1.0-dev #26864
Expected behavior:
Compile error at foo[0] = "blah" because the types of all indexes of the tuple should be readonly (this is the behavior in previous versions of Typescript, from at least 2.3 up to and including 3.0).
Actual behavior:
No compiler error. The type of foo is incorrectly reported as simply [string, number] rather than Readonly<[string, number]>, and the compiler allows the assignment.
Readonly tuple types never really worked correctly. Previously, when applying a mapped type (such as Readonly<T>) to a tuple type, we'd generate a type that is structurally similar to a tuple, but not actually assignable. For example:
constfoo: Readonly<[string,number]>=["hello",42];constbar: [string,number]=foo;// Now ok, previously would error
We now preserve the "tuple-ness" across mapped type applications (e.g. Partial<T> applied to a tuple actually does the right thing), but it means that the readonly-ness of the properties is lost because we have no inherent notion of tuples with readonly properties. To fix this issue we'd need to add a proper notion of readonly tuples--so, I'm going to label this a suggestion.
Reacted by Emily Marigold Klassen, Kaido Iwamoto, ulrichb, Alec Larson, Neonit and lin72h
Thanks for the explanation. That makes sense, but I still feel that this is a breaking change. It is causing "incorrect" behavior and failing dtslint tests on a project that has worked "correctly" and passed dtslint tests since TypeScript 2.3.
Even though Readonly tuples never really worked correctly, there was a subset of functionality that did work correctly (as one would expect in terms of observable behavior) prior to 3.1.0-dev. Now that mapped types are applied to tuples "correctly", some previous "observably correct" behavior with Readonly tuples has now been lost in exchange.
Please consider treating this more like a bug rather than an arbitrary suggestion or feature request.
I had a complete failure of the brain when trying to come up with the right terminology while writing my previous comment. I think the correct term to describe this issue is not just a "breaking change", but more specifically a "regression".
It may also be worth pointing out that if a version of TypeScript is released with the current behavior of 3.1.0-dev, then dtslint tests of types involving Readonly tuples will become complicated.
Sample setup code (quite a bit oversimplified compared to my real world examples just to focus on
examples of types involved, so ignore whether or not it would make sense for this function to return a readonly tuple, etc):
With TS 3.1.0-dev, the reported return value type of foo(blah) is ["a" | "b", number] instead of Readonly<["a" | "b", number]>.
The only way I can write dtslint tests that work with both 3.1.0-dev AND previous versions is to give up on dtslint type assertions, and fall back to less precise assignability tests, in addition to removing the test that attempts to assign a value to one of the tuple's indexes.
Even if a future version of TS re-introduces Readonly tuple behavior, I (and anyone else making use of Readonly tuple types) will be stuck with the less reliable assignability tests in dtslint in order to support validating previous versions of TS, and will need to write separate tests for this future version and beyond in order to precisely validate the type with an $ExpectType assertion.
Activity
ahejlsberg commentedon Sep 4, 2018
Readonly tuple types never really worked correctly. Previously, when applying a mapped type (such as
Readonly<T>) to a tuple type, we'd generate a type that is structurally similar to a tuple, but not actually assignable. For example:We now preserve the "tuple-ness" across mapped type applications (e.g.
Partial<T>applied to a tuple actually does the right thing), but it means that the readonly-ness of the properties is lost because we have no inherent notion of tuples with readonly properties. To fix this issue we'd need to add a proper notion of readonly tuples--so, I'm going to label this a suggestion.UselessPickles commentedon Sep 4, 2018
Thanks for the explanation. That makes sense, but I still feel that this is a breaking change. It is causing "incorrect" behavior and failing dtslint tests on a project that has worked "correctly" and passed dtslint tests since TypeScript 2.3.
Even though Readonly tuples never really worked correctly, there was a subset of functionality that did work correctly (as one would expect in terms of observable behavior) prior to 3.1.0-dev. Now that mapped types are applied to tuples "correctly", some previous "observably correct" behavior with Readonly tuples has now been lost in exchange.
Please consider treating this more like a bug rather than an arbitrary suggestion or feature request.
ahejlsberg commentedon Sep 4, 2018
Ryan Cavanaugh (@RyanCavanaugh) Daniel Rosenwasser (@DanielRosenwasser) Let's discuss how we want to prioritize this.
UselessPickles commentedon Sep 10, 2018
I had a complete failure of the brain when trying to come up with the right terminology while writing my previous comment. I think the correct term to describe this issue is not just a "breaking change", but more specifically a "regression".
It may also be worth pointing out that if a version of TypeScript is released with the current behavior of 3.1.0-dev, then dtslint tests of types involving Readonly tuples will become complicated.
Sample setup code (quite a bit oversimplified compared to my real world examples just to focus on
examples of types involved, so ignore whether or not it would make sense for this function to return a readonly tuple, etc):
And the corresponding dtslint test example that works in TS 3.0 an earlier:
With TS 3.1.0-dev, the reported return value type of
foo(blah)is["a" | "b", number]instead ofReadonly<["a" | "b", number]>.The only way I can write dtslint tests that work with both 3.1.0-dev AND previous versions is to give up on dtslint type assertions, and fall back to less precise assignability tests, in addition to removing the test that attempts to assign a value to one of the tuple's indexes.
Even if a future version of TS re-introduces Readonly tuple behavior, I (and anyone else making use of Readonly tuple types) will be stuck with the less reliable assignability tests in dtslint in order to support validating previous versions of TS, and will need to write separate tests for this future version and beyond in order to precisely validate the type with an $ExpectType assertion.