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
TypeScript now has a ES6 target mode which includes definitions Symbol. However when trying to index an object with a symbol, I get an error (An index expression argument must be of type 'string', 'number', or 'any').
vartheAnswer=Symbol('secret');varobj={};obj[theAnswer]=42;// Currently error, but should be allowed
Tomáš Čarnecký (@wereHamster), with pull request #1978, this should become legal, and obj[theAnswer] will have type any. Is that sufficient for what you are looking for, or do you need stronger typing?
Reacted by Eric Simonton, Nathan Phillip Brink, NaLLiFFuNT, Shaun Cutts, Russell Dempsey, Telokis, Greg, Alexander Mills, a1300, Francisco Castro and 5 more
I think Tomáš Čarnecký (@wereHamster) is talking about a stronger typing than Dan Quirk (@danquirk). There are 3 levels of support here. The most basic level is provided by my PR, but that is just for symbols that are properties of the global Symbol object, not user defined symbols. So,
vartheAnswer=Symbol('secret');interfaceDeepThought{[Symbol.toStringTag](): string;// Allowed[theAnswer]: number;// not allowed}
The next level of support would be to allow a symbol indexer:
vartheAnswer=Symbol('secret');interfaceDeepThought{[s: symbol]: number;}vard: DeepThought;d[theAnswer]=42;// Typed as number
This is on our radar, and can be implemented easily.
The strongest level is what you're asking for, which is something like:
This would be really nice, but so far we have not come up with a sensible design for it. It ultimately seems to hinge on making the type depend on the runtime value of these symbols. We will continue to think about it, as it is clearly a useful thing to do.
With my PR, you should at least be able to use a symbol to pull a value out of an object. It will be any, but you will no longer get an error.
Reacted by Russell Dempsey, Lucas Basquerotto, Telokis, John, Artha, Nathan Pennie, nyanpasu64, Mingwei Samuel, Scott Hardy and Niklas Kraßnig
I've merged request #1978, but I will leave this bug open, as it seems to ask for more than I provided with that change. However, with my change, the original error will go away.
Tomáš Čarnecký (@wereHamster) can you post an update of what more you'd like to see happen here? Wasn't immediately clear to me what we have implemented vs what you posted
Is there any explanation of this from typescript maintainers team?
I can't see any reason why this is not handled.
This is very useful when creating 3 party libraries.
Without this fix we'll have to use @ts-ignore comments all over the place
I'll reiterate my suggestion to make a TS language-level distinction between user-instantiated symbols and 'well-known' JS symbols.
Quoting myself from earlier:
Well-known symbols are just sentinels that happen to be implemented using Symbol. Unless the goal is object serialization or introspection, code probably should treat these sentinels different from other symbols, because they have special meaning to the language. Removing them from the symbol type will likely make (most) code using 'generic' symbols more safe.
Benjamin Riggs (@riggs) that would not fit a number of use cases; it's absolutely critical that everything for which typeof x === 'symbol' is in the symbol type, otherwise APIs can't be typed properly.
Reacted by ExE Boss, Nathan Phillip Brink, Toni Villena, Claudia Meadows and Serhii Mamedov
Given that TypeScript is a superset of JS created for the explicit purpose of type safety, create two new types, LanguageSymbol and Sentinel:
LanguageSymbol is the union of the 'well-known' static properties on Symbol.
Sentinel is every Symbol that isn't a LanguageSymbol.
Symbol remains untouched, but maybe gets a flag warning about direct usage in a future version.
Sentinels are, by definition, freed from the concerns relating to well-known symbols. Preserving this behavior at runtime does incur a small overhead, but would likely only occur when doing introspection, at which point extra care is likely warranted. I suspect most code doing runtime type checks for symbols are expecting to not be dealing with a LanguageSymbol in the first place.
Reacted by Claudia Meadows, ExE Boss, Serhii Mamedov, Jordan Harband and Simon Reinisch
Nit: TypeScript is not a superset of JS, nor it is a programming language; it specifies little in the way of behaviors. One can't "develop code in TS 4.2". One codes in eg. ES2015, with TS 4.2 specified type annotation syntax and ES2015 library types. Novice programmers can't learn to "code in TS". They learn to code in JS, with type annotations. No TS spec says anything about what [].map() does, and it can't, as the runtime is JS and what the [].map() does depends on the ES version, not on the TS version. The coder can't put TS expressions in the Dev Console and there's no TS REPL. One can't implement a cleanroom TypeScript interpreter or compiler. Specifying the TS version and not specifying the ES version leads to unclear runtime semantics.
TypeScript has no up to date specification, let alone standard, and Microsoft's own 2016 writeup hasn't been vetted by standards bodies and isn't nearly anything like the EcmaScript specification from which one can actually implement a complying and useful realization. This document claiming TS is "a superset of EcmaScript 2015" doesn't make it so. There has been a stated disinterest in a specification for the last 5 years. Everything is a tradeoff, and this can be a legit tradeoff, and something defined by its own implementation, rather than a spec, doesn't make it not a language, though the existence of an ES-like spec would help establish TS as a language.
To quote from the 2016 document, "[besides some class and module notations] TypeScript also provides to JavaScript programmers a system of optional type annotations. These type annotations are like the JSDoc comments". It's an affordance for JavaScript programmers.
TS is more of a type annotation overlay to assist code linting, which also happens to add minor shorthands to the JS syntax via transpilation, and in practice, remove significantly from JS capabilities too (because it makes certain patterns very hard or impossible to properly type annotate; eg. it allows extra properties). TS does not live independently of JS, it has no language spec. And sure, there's an associated toolchain with source code transformation (mostly, removes the type notations), linter, IDE plugins etc.
So it's best to think of TS
a linter friendly type notation syntax, with
rather partial type libraries for constructs of ES versions, and
a toolchain consisting of linters, pessimizing transpilers (slow, unneeded polyfills) etc., plus
some macros for localized JS syntax augmentation (eg. in class),
which altogether constrain the coding style to the subset of JS patterns that are somewhat conducive to the otherwise not well specified, and not particularly consistent so-called structural typing concepts
associated with TypeScript versions, which bundle specifics of the above things, but still isn't a superset of JS
Reacted by Mathieu CAROFF, ExE Boss, Anderson Slivinski, Andre Luiz Bellon-Jerpseth, Serhii Mamedov and Simon Reinisch
Activity
mhegazy commentedon Jan 30, 2015
That is part of the ES6 Symbol support we Jason Freeman (@JsonFreeman) is working on. Your code sample should be supported in the next release.
JsonFreeman commentedon Feb 9, 2015
Tomáš Čarnecký (@wereHamster), with pull request #1978, this should become legal, and
obj[theAnswer]will have typeany. Is that sufficient for what you are looking for, or do you need stronger typing?wereHamster commentedon Feb 9, 2015
Will it be possible to specify the type of properties which are indexed by symbols? Something like the following:
danquirk commentedon Feb 9, 2015
Based on the comments in that PR, no:
This does not cover symbol indexers, which allows an object to act as a map with arbitrary symbol keys.
JsonFreeman commentedon Feb 10, 2015
I think Tomáš Čarnecký (@wereHamster) is talking about a stronger typing than Dan Quirk (@danquirk). There are 3 levels of support here. The most basic level is provided by my PR, but that is just for symbols that are properties of the global Symbol object, not user defined symbols. So,
The next level of support would be to allow a symbol indexer:
This is on our radar, and can be implemented easily.
The strongest level is what you're asking for, which is something like:
This would be really nice, but so far we have not come up with a sensible design for it. It ultimately seems to hinge on making the type depend on the runtime value of these symbols. We will continue to think about it, as it is clearly a useful thing to do.
With my PR, you should at least be able to use a symbol to pull a value out of an object. It will be
any, but you will no longer get an error.JsonFreeman commentedon Feb 11, 2015
Tomáš Čarnecký (@wereHamster) I did a little writeup #2012 that you may be interested in.
JsonFreeman commentedon Feb 18, 2015
I've merged request #1978, but I will leave this bug open, as it seems to ask for more than I provided with that change. However, with my change, the original error will go away.
RyanCavanaugh commentedon Oct 5, 2015
Tomáš Čarnecký (@wereHamster) can you post an update of what more you'd like to see happen here? Wasn't immediately clear to me what we have implemented vs what you posted
kitsonk commentedon Dec 31, 2015
Any idea when
symbolwill be valid type as an indexer? Is this something that could be done as a community PR?96 remaining items
devinrhode2 commentedon Nov 3, 2020
Nhu H Trinh (@james4388) How is your example any different from the one from Beeno Tung (@beenotung)?
dead-claudia commentedon Nov 8, 2020
FYI: #26797
(Just found it - I'm not actually part of the TS team.)
monfera commentedon Dec 29, 2020
I agree that if this is safe:
then the analogous
is also safe
Gnucki commentedon Jan 29, 2021
My poor workaround for some cases :
ExE-Boss commentedon Jan 30, 2021
Thomas Prelot (@Gnucki) It’s probably better to do, since the
as anytype assertion gets removed during compilation:which compiles to:
Whereas your code compiles to:
which causes the local DeclarativeEnvironmentRecord to have two
constbindings pointing to the same Symbol value.repugraf commentedon Mar 3, 2021
Is there any explanation of this from typescript maintainers team?
I can't see any reason why this is not handled.
This is very useful when creating 3 party libraries.
Without this fix we'll have to use
@ts-ignorecomments all over the placeriggs commentedon Mar 4, 2021
I'll reiterate my suggestion to make a TS language-level distinction between user-instantiated symbols and 'well-known' JS symbols.
Quoting myself from earlier:
ljharb commentedon Mar 4, 2021
Benjamin Riggs (@riggs) that would not fit a number of use cases; it's absolutely critical that everything for which
typeof x === 'symbol'is in thesymboltype, otherwise APIs can't be typed properly.riggs commentedon Mar 14, 2021
Given that TypeScript is a superset of JS created for the explicit purpose of type safety, create two new types,
LanguageSymbolandSentinel:LanguageSymbolis the union of the 'well-known' static properties onSymbol.Sentinelis every Symbol that isn't aLanguageSymbol.Symbol remains untouched, but maybe gets a flag warning about direct usage in a future version.
Sentinels are, by definition, freed from the concerns relating to well-known symbols. Preserving this behavior at runtime does incur a small overhead, but would likely only occur when doing introspection, at which point extra care is likely warranted. I suspect most code doing runtime type checks for symbols are expecting to not be dealing with a
LanguageSymbolin the first place.monfera commentedon Mar 16, 2021
Nit: TypeScript is not a superset of JS, nor it is a programming language; it specifies little in the way of behaviors. One can't "develop code in TS 4.2". One codes in eg. ES2015, with TS 4.2 specified type annotation syntax and ES2015 library types. Novice programmers can't learn to "code in TS". They learn to code in JS, with type annotations. No TS spec says anything about what
[].map()does, and it can't, as the runtime is JS and what the[].map()does depends on the ES version, not on the TS version. The coder can't put TS expressions in the Dev Console and there's no TS REPL. One can't implement a cleanroom TypeScript interpreter or compiler. Specifying the TS version and not specifying the ES version leads to unclear runtime semantics.TypeScript has no up to date specification, let alone standard, and Microsoft's own 2016 writeup hasn't been vetted by standards bodies and isn't nearly anything like the EcmaScript specification from which one can actually implement a complying and useful realization. This document claiming TS is "a superset of EcmaScript 2015" doesn't make it so. There has been a stated disinterest in a specification for the last 5 years. Everything is a tradeoff, and this can be a legit tradeoff, and something defined by its own implementation, rather than a spec, doesn't make it not a language, though the existence of an ES-like spec would help establish TS as a language.
To quote from the 2016 document, "[besides some class and module notations] TypeScript also provides to JavaScript programmers a system of optional type annotations. These type annotations are like the JSDoc comments". It's an affordance for JavaScript programmers.
TS is more of a type annotation overlay to assist code linting, which also happens to add minor shorthands to the JS syntax via transpilation, and in practice, remove significantly from JS capabilities too (because it makes certain patterns very hard or impossible to properly type annotate; eg. it allows extra properties). TS does not live independently of JS, it has no language spec. And sure, there's an associated toolchain with source code transformation (mostly, removes the type notations), linter, IDE plugins etc.
So it's best to think of TS
class),DanielRosenwasser commentedon Mar 16, 2021
We're working on an implementation, but the conversation here isn't useful nor is it contributing anything to the implementation.
ahejlsberg commentedon Jun 21, 2021
Implemented in #44512 which is now in the main branch.