-
Notifications
You must be signed in to change notification settings - Fork 12.8k
unique symbols are downgraded simple symbols when they pass through destructuring #53753
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? # to your account
Comments
Investigating a bit, the problem seems to come from destructuring. Any intermediary assignation seems to fail const s: unique symbol = Symbol();
const t = s;
const ss: typeof s = t; |
This can be inferred correctly with a const context const s: unique symbol = Symbol();
const t: Promise<typeof s> = Promise.race([s] as const); |
Unique symbols consistently follow the same widening rules as literals, which includes widening in places like non- |
@RyanCavanaugh : I can see that. But don't you think this is a problem ? This leads to a surprising behavior that is probably not what the user wants in most cases. const x : unique symbol = Symbol("x");
const y = x; // is there any case in which someone wants to have a generic symbol instead of the unique symbol "x" here ? Are there pieces of code in which the default behavior here makes sense ? |
Plus, the rules don't seem to be exactly the same, because the following works as intended: const s: 1 = 1;
const t: Promise<typeof s> = Promise.race([s]); |
This has been the behavior since we first shipped unique symbols over five years ago and I've seen at most a handful of complaints that this is unintuitive.
It's impossible for zero people to be surprised by something.
Sure, for example if you have const s: unique symbol = Symbol();
export function fn() {
return s;
} the inferred type of |
I didn't want to be provocative, sorry if my tone was off. const s: unique symbol = Symbol();
export function fn(): typeof s {
return s;
} How would that leak an implementation detail ? The symbol itself is returned to the user and leaked anyway. I am struggling to see an example where leaking the value would be fine but leaking its type would be an issue. Is there any real-world code where it would be a problem ? With the default behavior, APIs like this become broken, without it being obvious to the user: export function fn() { return s }
export function accept(x: typeof s) { } // This function becomes impossible to use
const s: unique symbol = Symbol(); // replacing "unique symbol" by a literal type and Symbol() by a literal value results in a different behavior If the behavior is set in stone because it was released like that, then maybe that should be highlighted in the docs, since it is (at least to simple users like me) surprising and unlike other parts of typescript. |
This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes. |
Bug Report
unique symbol
seems to lose its uniqueness when it goes throughPromise.race
π Search Terms
Awaited unique symbol typescript
π Version & Regression Information
typescript version 5.0.4
β― Playground Link
Playground link with relevant code
π» Code
π Actual behavior
The code above should type check
π Expected behavior
t
should end up with typePromise<unique symbol>
instead ofPromise<symbol>
The text was updated successfully, but these errors were encountered: