-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Prevent readonly symbols widening #54778
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Prevent readonly symbols widening #54778
Conversation
@@ -37570,7 +37570,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | |||
} | |||
|
|||
function widenTypeInferredFromInitializer(declaration: HasExpressionInitializer, type: Type) { | |||
const widened = getCombinedNodeFlagsCached(declaration) & NodeFlags.Constant || isDeclarationReadonly(declaration) ? type : getWidenedLiteralType(type); | |||
const widened = getCombinedNodeFlagsCached(declaration) & NodeFlags.Constant || isDeclarationReadonly(declaration) ? type : getWidenedUniqueESSymbolType(getWidenedLiteralType(type)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that perhaps as const
should preserve the uniqueness of symbols created in object literals but that's not strictly related to this issue so I think it should be fine to tackle this separately if that's something that you think should be done.
// always widen a 'unique symbol' type if the type was created for a different declaration. | ||
if (type.flags & TypeFlags.UniqueESSymbol && (isBindingElement(declaration) || !declaration.type) && type.symbol !== getSymbolOfDeclaration(declaration)) { | ||
// always widen a 'unique symbol' type if the type was created for a different declaration and if it isn't accessible | ||
if (type.flags & TypeFlags.UniqueESSymbol && !declaration.type && type.symbol !== getSymbolOfDeclaration(declaration) && !isValueSymbolAccessible(type.symbol, type.symbol.valueDeclaration)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a feeling that passing type.symbol.valueDeclaration
to isValueSymbolAccessible
here might not be 100% correct but so far I wasn't able to write a test that would fail with this
@jakebailey would u mind creating a playground for this one? :) |
@typescript-bot pack this |
Heya @jakebailey, I've started to run the tarball bundle task on this PR at d7dc3f9. You can monitor the build here. |
Hey @jakebailey, I've packed this into an installable tgz. You can install it for testing by referencing it in your
and then running There is also a playground for this build and an npm module you can use via |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hrm, when I opened the original issue I had a specific kind of fix in mind - right now all literal types have "freshness" that determines if we widen them or not at specific locations. unique symbol
s are literal types which currently lack fresh and un-fresh variants, and instead just always widen (and always widen in more places than most other literal types do). Freshness for unique symbols is a bit more complicated though - they don't come from a literal, per sey, so it's not that expression literals produce fresh types, but rather that the Symbol()
call and... const assignments of unique symbol
s (? or at least references to members of the global Symbol
constructor?) produce "fresh" (widening) variants of the types.
In any case, I don't feel great about widening being controlled by an accessibility check - that's probably not good for perf, and doesn't actually check completely what you'd hope it does - it checks if the symbol is accessible via simple dotted accesses from a name at the given location, but the symbol may, for example, be a member of a type and is thus still "accessible" but via an indexed access on a type symbol... or something more convoluted. I just don't feel like accessibility determining widening behavior has great rules or a great feel, and doesn't feel like it can be reliably replicated into a declaration file to preserve the widening behavior.
I dunno, I've talked about it before among the team and maybe @rbuckton has more thoughts on why unique symbols so aggressively widen today.
How would the narrowed-down fix for your issue look like? Checking if it comes from the global |
Note: this PR blocks #42104. @weswigham would you be able to look at this again? It sounds like you wanted quite a different approach from what's currently here. |
I think this predated our design meeting in which we basically said "symbol should do widening just like literals but doesn't" such that a final fix will probably be to rework symbols to have some sort of freshness. I just haven't had time to do so. That or I've misunderstood the situation. |
If you are already committed to this kind of change then it's probably best to close this PR. |
closes #53276 , cc @weswigham