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
It seems to me that type for primitive value assigned to a const variable gets widened in some contexts - I'm not 100% sure if this is a bug report or feature request, but this is a bit counterintuitive. Is this an expected behaviour?
(From what I saw in the playground hints, primitive values assigned to const behave as if they had as const modifier)
constTYPE_1='TYPE_1';constTYPE_2='TYPE_2'asconst;constaction1={type: TYPE_1};constaction2={type: TYPE_2};action1.type='string'// Why does this throw? It's not a readonly prop, so it should have inferred 'string'action2.type='string'
I'm not 100% sure this is the case, the playground hints that type of const TYPE_1 = 'TYPE_1' is "TYPE_1". This example would suggest that it's not getting widened:
const TYPE_1 = 'TYPE_1';
function fn() {
switch (TYPE_1) {
case TYPE_1:
return 4;
case 'any': // Type '"any"' is not comparable to type '"TYPE_1"'.(2678)
return 5;
}
}
I may not understand correctly what it means for a type to be widening, but it seems a rather inconsistent behaviour if working as intended. I would've expected the type won't change depending on the use case
It is a bit odd that the widening flag is apparently being preserved in the type of a const, though. This widening behavior is only supposed to apply to fresh literals.
This issue has been marked as 'Question' and has seen no recent activity. It has been automatically closed for house-keeping purposes. If you're still waiting on a response, questions are usually better suited to stackoverflow or the TypeScript Discord community.
Ryan Cavanaugh (@RyanCavanaugh) that felt a bit rough :D It's not a question, and doesn't belong to stackoverflow.
I don't think it's good that primitive value assigned to const is (allegedly) of literal type value, and then information about the type is lost. I'm not sure if the problem lies in what types are reported (of the const variable) or if type is lost (either is a bug), and I'd probably expect that the type is actually literal for primitives assigned to const since they can't be (meaningfully) reassigned. (Feature request?)
I'd vastly appreciate if you could kindly reopen it. I'm happy to accept suggestions to issue title/description changes, if they are confusing.
Piotr Staniów (@TeoTN) the difference in behavior, which is intentional, was correctly described by Bruce Pascoe (@fatcerberus) above. There is a difference between the widening and non-widening forms of literals, which isn't displayed in the UI (we discussed this and decided that it would be more confusing, rather than less, on net).
Ryan Cavanaugh (@RyanCavanaugh) I find it odd that the “widening literal” flag gets preserved through a const declaration. That’s very confusing since it’s not reflected in any way in the type of the variable. This seems analogous to if object literal freshness were preserved by a const declaration, which would be just as confusing.
The intuition is that this program should not have an error:
consta="foo";constb={prop: a};b.prop="bar";
The widening rules for literals were largely derived empirically, since code like this predates the existence of literal types. One way to think about it is that it should be extremely difficult to get yourself into a literal type mismatch if none of your code contains either an as const or a literal type declaration somewhere in it.
If I'm misunderstanding your observation let me know; happy to clarify.
I guess that makes sense. I think I would rather have const a itself be widened to string (like what happens with let) rather than the potentially confusing deferred widening, but that would be a breaking change at this stage so I won’t suggest it.
Activity
DuncanWalter commentedon Mar 24, 2022
Another way to express the issue (I think this is the same issue at least):
Playground
whzx5byb commentedon Mar 24, 2022
const TYPE_1 = 'TYPE_1'have a widening type, whileconst TYPE_2 = 'TYPE_2' as consthave a non-widening literal type.See #10676, #29510 for more details.
TeoTN commentedon Mar 24, 2022
I'm not 100% sure this is the case, the playground hints that type of
const TYPE_1 = 'TYPE_1'is"TYPE_1". This example would suggest that it's not getting widened:I may not understand correctly what it means for a type to be widening, but it seems a rather inconsistent behaviour if working as intended. I would've expected the type won't change depending on the use case
fatcerberus commentedon Mar 24, 2022
What you're ultimately observing is the difference between:
It is a bit odd that the widening flag is apparently being preserved in the type of a
const, though. This widening behavior is only supposed to apply to fresh literals.typescript-bot commentedon Mar 28, 2022
This issue has been marked as 'Question' and has seen no recent activity. It has been automatically closed for house-keeping purposes. If you're still waiting on a response, questions are usually better suited to stackoverflow or the TypeScript Discord community.
TeoTN commentedon Mar 28, 2022
Ryan Cavanaugh (@RyanCavanaugh) that felt a bit rough :D It's not a question, and doesn't belong to stackoverflow.
I don't think it's good that primitive value assigned to const is (allegedly) of literal type value, and then information about the type is lost. I'm not sure if the problem lies in what types are reported (of the const variable) or if type is lost (either is a bug), and I'd probably expect that the type is actually literal for primitives assigned to
constsince they can't be (meaningfully) reassigned. (Feature request?)I'd vastly appreciate if you could kindly reopen it. I'm happy to accept suggestions to issue title/description changes, if they are confusing.
RyanCavanaugh commentedon Mar 28, 2022
Piotr Staniów (@TeoTN) the difference in behavior, which is intentional, was correctly described by Bruce Pascoe (@fatcerberus) above. There is a difference between the widening and non-widening forms of literals, which isn't displayed in the UI (we discussed this and decided that it would be more confusing, rather than less, on net).
fatcerberus commentedon Mar 28, 2022
Ryan Cavanaugh (@RyanCavanaugh) I find it odd that the “widening literal” flag gets preserved through a
constdeclaration. That’s very confusing since it’s not reflected in any way in the type of the variable. This seems analogous to if object literal freshness were preserved by aconstdeclaration, which would be just as confusing.RyanCavanaugh commentedon Mar 28, 2022
The intuition is that this program should not have an error:
The widening rules for literals were largely derived empirically, since code like this predates the existence of literal types. One way to think about it is that it should be extremely difficult to get yourself into a literal type mismatch if none of your code contains either an
as constor a literal type declaration somewhere in it.If I'm misunderstanding your observation let me know; happy to clarify.
fatcerberus commentedon Mar 29, 2022
I guess that makes sense. I think I would rather have
const aitself be widened tostring(like what happens withlet) rather than the potentially confusing deferred widening, but that would be a breaking change at this stage so I won’t suggest it.RyanCavanaugh commentedon Mar 29, 2022
We tried the simple thing (both simple things, actually) and they didn't work ergonomically in practice. See discussions at #10898, #11126, and #10676