-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Allow functions to have new symbol
as the return type
#37469
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
Comments
You can sort of get around it using some epik type-level hax, but I don't know if
|
unique symbol
as the return typeunique symbol
or new symbol
as the return type
I tried everything even @Shou's hack. There is no work around and we def need some changes. My biggest issue is that when you destructure an array of unique symbols, typescript no longer considers them unique.. And there is no way to force typescript to consider them unique. // What I originally expected to work
const [$arr, $head, $tail] = 'array head tail'.split(' ').map(Symbol.for);
// A computed property name in a class property declaration must refer to an expression whose type is a literal type or a 'unique symbol' type.ts(1166)
interface TestClass { [$arr]: boolean; } // using interface for this test because then I don't have to come up with new name for each example
// Can't cast to unique symbol. Err: 'symbol' expected.ts(1005)
const [$arrAofUS, $headAofUS, $tailAofUS] = 'array head tail'.split(' ').map(Symbol.for) as unique symbol[];
const [$arrCAofUS, $headCAofUS, $tailCAofUS] = 'array head tail'.split(' ').map(Symbol.for) as Array<unique symbol>;
// A computed property name in an interface must refer to an expression whose type is a literal type or a 'unique symbol' type.ts(1169)
interface TestClass { [$arrAofUS]: boolean; [$arrCAofUS]: boolean; }
// None of these work either
const [$arrEAofS, $headEAofS, $tailEAofS] = 'array head tail'.split(' ').map(Symbol.for) as [symbol, symbol, symbol];
// 'unique symbol' types are not allowed here.ts(1335)
const [$arrEAofUS, $headEAofUS, $tailEAofUS] = 'array head tail'.split(' ').map(Symbol.for) as [unique symbol, unique symbol, unique symbol];
// A computed property name in an interface must refer to an expression whose type is a literal type or a 'unique symbol' type.ts(1169)
interface TestClass { [$arrEAofS]: boolean; [$arrEAofUS]: boolean; }
// It's not the split messing it up. Error: 'unique symbol' types are not allowed here.ts(1335)
const [$arrAM, $headAM, $tailAM] = ['array', 'head', 'tail'].map(Symbol.for);
// Doesn't work with destructuring!
const [$arrD, $headD, $tailD] = ([Symbol.for('array'), Symbol.for('head'), Symbol.for('tail')]);
// A computed property name in an interface must refer to an expression whose type is a literal type or a 'unique symbol' type.ts(1169)
interface TestClass { [$arrAM]: boolean; [$arrD]: boolean; }
// Even when trying @Shou's hack
type UniqueSymbol = ReturnType<(a: string) => { readonly 0: unique symbol }[0]>;
// testing if UniqueSymbol works on the simple cases
// NOPE! Err: Type 'typeof $test' is not assignable to type 'typeof 0'.ts(2322)
const $testCustomUniqueSymbol: UniqueSymbol = Symbol.for('test');
// This does if it's casted before assignment
const $testCastedCustomUniqSym: UniqueSymbol = Symbol.for('test') as UniqueSymbol;
// but it's still not a unique symbol! Err: Type 'typeof 0' is not assignable to type 'typeof $testUniqSym'.ts(2322)
const $testNativeUniqSym: unique symbol = $testCustomUniqueSymbol;
// however it does work for regular symbol
const $testNativeSym: symbol = $testNativeUniqSym;
// Attempt at destructuring again, and even explicit casting
const [$arrFnUS, $headFnUS, $tailEFnUS]: [UniqueSymbol, UniqueSymbol, UniqueSymbol] = 'array head tail'.split(' ').map(Symbol.for) as [UniqueSymbol, UniqueSymbol, UniqueSymbol];
interface TestClass {
[$testCustomUniqueSymbol]: boolean; // Works so we know our UniqueSymbol type works for some cases
[$testCastedCustomUniqSym]: boolean; // Works
[$testNativeUniqSym]: boolean; // Works
// Surprised testNativeSym doesn't work!
[$testNativeSym]: boolean; // Err: A computed property name in an interface must refer to an expression whose type is a literal type or a 'unique symbol' type.ts(1169)
[$arrFnUS]: boolean; // Err: A computed property name in an interface must refer to an expression whose type is a literal type or a 'unique symbol' type.ts(1169)
}
// Attempts to hack around it:
// Err: Type 'symbol[]' is not assignable to type '(unique symbol)[]'. Type 'symbol' is not assignable to type 'unique symbol'.ts(2322)
const toSymArr = (str: string): UniqueSymbol[] => str.split(' ').map(Symbol.for);
// hack around the error
const toSymArr2 = (str: string): UniqueSymbol[] => str.split(' ').map(Symbol.for) as any;
// will it work?
const [$arrFn, $headFn, $tailFn] = toSymArr('array head tail');
// nope! Err: A computed property name in an interface must refer to an expression whose type is a literal type or a 'unique symbol' type.ts(1169)
interface TestClass { [$arrFn]: boolean; } |
I need this feature do define a method of a collection class that creates unique tokens for each of its items: interface Entry<Value> {
readonly id: unique symbol;
value: Value;
}
class Collection<Item> {
private entriesMap = new Map<symbol, Entry<Item>>();
private createEntryID(): symbol {
const id: unique symbol = Symbol('item');
return id;
}
add(item: Item): void {
const id = this.createEntryID();
// `symbol`, cannot be casted to `unique symbol`
const entry: Entry<Item> = {
value: item,
id,
// ^ Error: Type 'symbol' is not assignable to type 'unique symbol'.
};
this.entriesMap.set(id, entry);
}
} So far, I can only fix this by ditching the interface Entry<Value> {
readonly id: symbol;
value: Value;
} … and, since I don't much understand Starting a new season of the "How much "more feedback" do you need, @RyanCavanaugh" series 😉 |
Relative to the cost here, quite a bit more 🙃. 15 upvotes and 3 comments in two years is not a lot. |
unique symbol
or new symbol
as the return typeunique symbol
~ or new symbol
as the return type
unique symbol
~ or new symbol
as the return typenew symbol
as the return type
This bug affects a system in Transcend Consent for securely exposing subsets of class APIs to untrusted third party scripts. We have a |
Search Terms
Suggestion
I request that
unique symbol
be allowed as the return type of a function declaration.Alternatively, it might be better to use
new symbol
to disambiguate #40106 (comment).Use Cases
Currently, it’s impossible to create an alias or a wrapper function for the global
Symbol
constructor and use that to construct unique symbols:Examples
This would allow defining
SymbolConstructor
as:Checklist
My suggestion meets these guidelines:
See also
Symbol
value to refer to its properties in the same manner or create unique symbols #36468global symbol "<name>"
proposal)The text was updated successfully, but these errors were encountered: