-
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
allow string literals (unions of string literals?) as a type of an indexer #7656
Comments
I also encountered this and considered opening an issue, though having a string literal union as a key type would have very similar semantics to: type Keyed<a> = { this?: a; that?: a } Which would appear a bit more verbose and require more typing though. However, the indexer approach does have the advantage that it allows aliasing the key type (the string literal union) separately, e.g: type RequestMethod = "GET" | "SET" | "PUT" | "UPDATE" | "DELETE";
type HandlerObject = { [key: RequestMethod]: (requestObject: RequestObject) => boolean; }; I think that based on the usefulness of this particular pattern it should definitely be considered to become valid syntax. Also, the same pattern may also prove useful when the numeric literal type is introduced: type ValidNumericKey = 1 | 2 | 4 | 8 | 16;
type ValueObject = { [key: ValidNumericKey]: SomeObject }; |
it's not an equivalent, my Keyed can take from 0 through 1 to 2 values, completely different semantics
|
I was just about to fix it when you replied. I changed it to make all properties optional, though it may still not have the same exact semantics, but the difference may be subtle. Can you think of any other differences? |
Well there's one difference (that's isn't really about semantics) that the interface style notation, based on current behavior, would allow using the dot ( type Keyed1<a> = { this?: a; that?: a }
type Keyed2<a> = { [key: 'this' | 'that']: a; }
let x: Keyed1<number> = {};
let y: Keyed2<number> = {};
x['that'] = 34; // OK
x.that = 34; // OK
y['that'] = 34 // OK
y.that = 34 // Error However that behavior could be changed in case the key is a string literal, I guess, perhaps, maybe? |
Can you explain what you expect this to do? Is it equivalent to this? type Keyed<a> = { 'this': a } | { 'that': a }; |
I believe (though of course I may be subtly wrong) the idea is that the string literal union constrains what keys can be used to a finite set, in this case type Keyed = { [key: 'this' | 'that']: number; } I believe the possible values for x = {};
// or
x = { 'this': ...some number... }
// or
x = { 'that': ...some number... }
//or
x = { 'this': ...some number..., 'that': ...some number... } |
So |
Based on my understanding that would seem like the most natural interpretation of this combination of the indexer syntax and the concept of string literal union applied to the key. It also seems like this may mean that unlike the semantics of an "normal" interface this would be a strict type, i.e. not assignable from a wider type (having additional properties)? |
Or the fact it's still enclosed within the "brackets" |
why? to limit the possible set of keys, prevent unexpected keys from
|
I'm sort of rethinking this. Perhaps we need to separate the two different aspects of semantics here:
|
I think we have a bigger problem here: it seems like indexer key types are not even checked for conventional types like These two examples don't induce any errors whatsoever (tested on playground and 1.8.7): type A = {[key: number]: any};
let a: A = {};
a["abcd"] = 1; // No error?
let x = a["abcd"]; // No error? type B = {[key: string]: any};
let b: B = {};
b[123] = 1; // No error?
let y = b[123]; // No error? |
This comment in #7660 is a direct continuation of the discussion here, but applied to the more general issue of the how strictly should index signature keys be type-checked. |
The text was updated successfully, but these errors were encountered: