-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Type 'symbol' cannot be used as an index type. #24587
Comments
@prshreshtha just write const sym = Symbol('sym'); or if you must type annotate, write const sym: unique symbol = Symbol('sym'); we forbid symbols as indexers because we have no symbol index signatures (this was a hole we patched in 2.9 - previously it would assume the string indexer type, which was very incorrect), however unique symbols - a type associated with exactly one symbol are fine, since they refer to exactly one property. |
@weswigham both of your suggestions produce |
Yeah.... We don't have symbol index signatures, and a |
Hmm. So this code working pre Shouldn't you always be able to index a property by Oddly enough, the following works: let x: { [key in symbol]: string }; // typeof x is {}
x[Symbol()] = new Date();
x['hello'] = 'world'; But this doesn't: let x: { [key in symbol | string]: string }; // typeof x is { [key: string]: string }
x[Symbol()] = 'value';
x['hello'] = 'world'; |
Conceptually yes - the actual machinery to make it work was never in place - the symbols were just being mistaken for strings.
Yeah, that's because square bracket accesses to const sym: unique symbol = Symbol('sym');
const x: {} = {};
x[sym] = 42;
x["no"] = 12; I don't know how to feel about it, personally, but it's been "a way out" of the type checker for awhile. Usages are an error under
Yeah, since the mapped type maps over |
Got it. Thanks for the detailed explanation. |
I have a question which is similar to this issue, I believe. I author a library containig a similar class like With typescript 2.9.x this will result in Is there any way of doing this properly? edit: const sbl: any = Symbol.for('content'); // With `any` it will work
interface MyObject {
someProperty: string;
another: number;
[key: string]: any;
}
class MyObject {
constructor(content: any) {
this[sbl] = content; // Type 'unique symbol' cannot be used as an index type.
Object.keys(content).forEach((key) => {
// This is in fact more complex ;-)
Object.defineProperty(this, key, {
get: () => this[sbl][key],
set: (val: any) => this[sbl][key] = val,
});
});
}
}
export default MyObject;
const obj = new MyObject({ test: 'content' });
console.log(obj.test); // Property 'test' does not exist on type 'MyObject'. |
Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed. |
@simon-scherzinger You probably want something more along the lines of const sbl = Symbol('content');
interface MyObject<T> {
someProperty: string;
another: number;
[sbl]: T;
[key: string]: any;
}
class MyObject<T> {
constructor(content: T) {
this[sbl] = content;
Object.keys(content).forEach((key) => {
// This is in fact more complex ;-)
Object.defineProperty(this, key, {
get: () => this[sbl][key],
set: (val: any) => this[sbl][key] = val,
});
});
}
}
export default MyObject;
const obj = new MyObject({ test: 'content' });
console.log(obj.test); // `any` |
…rious error messages. (The problem has been fixed, but doesn't appear to have landed in TS yet.)
@weswigham @mhegazy Do we have any spec that describes that this behavior is intended?
According to refs above consider following use case. I am implementing DI container where i would like to provide library users ability to use Symbols as keys(to avoid components collision) for their components. In my code I have something like: Could someone provide strong argumentation why it's not a bug in compiler and this code shouldn't work? |
For the unbearable change, I gotta write a ugly line like: const DEFAULT_LEVEL: string = Symbol("__default__") as any; What a stupid shit... |
Can't believe that shit works. Had to use const ItemId: string = Symbol('Item.Id') as unknown as string;
type Item = Record<string, string>;
const shoes: Item = {
name: 'whatever',
}
shoes[ItemId] = 'randomlygeneratedstring'; // no error { name: 'whatever', [Symbol(Item.Id)]: 'randomlygeneratedstring' } |
…n latest npm TS release (3.5.2): see also microsoft/TypeScript#1863 + microsoft/TypeScript#24587 + https://www.typescriptlang.org/docs/handbook/symbols.html
Can't imagine how it could be marked as "work as intended", since we have this "TypeScript is a typed superset of JavaScript" on main page. This is definitely a bug in a type system and should be fixed somehow. |
@mhegazy why you labling it "Working as Intended"? |
This issue seems mislabeled, but the main issue is #1863 and it's still open (and stalled apparently). |
Seems to be fixed by #44512 ! Available in |
TypeScript Version: 3.0.0-dev.20180601
Code
Expected behavior:
No errors.
tsc --target es6 symbol-index.ts
works with2.8.4
.Actual behavior:
symbol-index.ts(4,3): error TS2538: Type 'symbol' cannot be used as an index type.
when running
tsc --pretty false --target es6 symbol-index.ts
with2.9.1
ornext
.Playground Link: http://www.typescriptlang.org/play/#src=const%20x%3A%20Record%3Ckeyof%20any%2C%20string%3E%20%3D%20%7B%7D%3B%0D%0Ax%5B'hello'%5D%20%3D%20'world'%3B%0D%0Aconst%20sym%3A%20symbol%20%3D%20Symbol('sym')%3B%0D%0Ax%5Bsym%5D%20%3D%20'symbol%20string'%
The text was updated successfully, but these errors were encountered: