-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Can't evaluate equality of symbols made by Symbol.for #35909
Comments
Example // npm package A@v1
namespace A1 {
// Structural hidden field across versions and packages.
const tag = Symbol.for('TagName');
export class A<T> {
constructor(arg: T) { }
[tag]: T;
}
}
// npm package A@v2
namespace A2 {
// Structural hidden field across versions and packages.
const tag = Symbol.for('TagName');
export class A<T> {
constructor(arg: T) { }
[tag]: T;
}
export declare function f(a: A<'a'>): void;
}
// npm package B
namespace B {
A2.f(new A1.A('a')); // Should work.
} // npm package A
namespace A {
// Structural hidden field across versions and packages.
const tag = Symbol.for('TagName');
export class A<T> {
constructor(arg: T) { }
[tag]: T;
}
}
// npm package B
namespace B {
// Structural hidden field across versions and packages.
const tag = Symbol.for('TagName');
export class B<T> {
constructor(arg: T) { }
[tag]: T;
}
}
// npm package C
namespace C {
declare function f(a: A.A<'a'>): void;
f(new B.B('a')); // Should work.
} |
Like we have const foo: global symbol "<name>"; This would allow declaring Node’s built-in symbols as: declare module "util" {
namespace inspect {
// https://github.com/nodejs/node/issues/20821
const custom: global symbol "nodejs.util.inspect.custom";
}
namespace promisify {
// https://github.com/nodejs/node/issues/31647
const custom: global symbol "nodejs.util.promisify.custom";
}
} |
It's a bug I just stumbled upon and it was really surprising. |
It’s the intended behaviour for |
Sounds like it's not expected, more like an unforeseen side effect of adding unique symbols. |
I was looking at code for library and noticed usage of Symbol and Symbol.for I was curious what the difference was and found this https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/for I then attempted to try it in typescript and erroneously get the error that the conditional will alwasy be false even when the value is actually true. |
Is the problem that there is no concept of a "symbol literal" in TypeScript? It would be really nice to have a literal syntax for symbols which would type just like any other primitive literal like Syntax is arbitrary, but using const something = @something; //=> Symbol.for("something")
const somethingElse = @"something.else"; //=> Symbol.for("something.else")
const object: { [something]: string } = { @something: 'hello' }; Seems like this would ease a lot of pain in matching types that use well known symbols as keys. But even in the absence of a literal syntax, what would it take for TS to treat |
@cowboyd That would risk big conflicts with decorators, but a while ago I was thinking about the declare function Symbol.for<T extends string>(name: T): symbol T;
declare function Symbol.keyFor<T extends string>(sym: symbol T): T;
declare function Symbol.keyFor(sym: symbol): string | undefined;
let a = Symbol.for("foo"); // type is `symbol "foo"`
let b: symbol "foo" = Symbol.for("bar"); // error
let c = Symbol.for("baz" as string); // symbol string
let d: symbol = Symbol.for("foo"); // ok, symbol T is a subtype of symbol
let d: symbol "foo" = Symbol(); // error
let descA: "foo" = Symbol.keyFor(a); // ok
let descB: "bar" = Symbol.keyFor(a); // err, "foo" is not assignable to "bar" EDIT: I just noticed that this was already suggested at #35909 (comment) 😬 |
@nicolo-ribaudo you're definitely right, and the I like your suggestions. Also need to consider the difference between let a = Symbol("foo") // type is `unique symbol "foo"`
let b = Symbol.for("foo") // type is `symbol for "foo"` Anyhow, as you noted @ExE-Boss already suggested this.... wonder why this thread petered out? Is there something that we can do? |
Throwing in a use case here: I've got a library that exports a symbol for purposes of interop, that other code can declare methods with that symbol, without needing to depend on the library that defines the symbol. But then, in a project that uses both of those libraries, Typescript can't tell that module 2 implements the interface specified by module 1, even though it uses the same Symbol.for(). As it stands, the only way to get this kind of interop is with strings, not symbols, as there's no "global symbol" or "symbol for" syntax in Typescript. Using |
Excerpting from #60944, as I believe it's worth mentioning here:
|
This is also an obstacle of branded types and ghost types. I think resolving this problem is easy because these types are just a new literal type similar to string literal types.
TypeScript Version: 3.7.x-dev.20191228
Search Terms:
Code
Expected behavior:
no error
Actual behavior:
Type 'typeof b' is not assignable to type 'typeof a'.
This condition will always return 'false' since the types 'typeof a' and 'typeof b' have no overlap.
Playground Link: https://www.typescriptlang.org/play/index.html?ts=3.8.0-dev.20191228&ssl=1&ssc=1&pln=4&pc=18#code/MYewdgzgLgBAhjAvDAygTwLYCMQBsB0AZiAE4AUA5BQJQDcAUKJLFkqpjgceVXY+NBjAAXDChoADgFMQhGK2TpseIqUo1aMAPRaYUkiVL0EiU-M069B0kA
Related Issues: #35200
The text was updated successfully, but these errors were encountered: