Skip to content
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

Explicit string indexing access of map type #26974

Closed
mikecann opened this issue Sep 8, 2018 · 6 comments
Closed

Explicit string indexing access of map type #26974

mikecann opened this issue Sep 8, 2018 · 6 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@mikecann
Copy link

mikecann commented Sep 8, 2018

TypeScript Version: 3.1.0-dev.201xxxxx

Search Terms:

string index, explicit index

Code

type EventDefinitions<TEventPayload extends object> = {
    [eventName: string]: TEventPayload;
  };

type X = keyof EventDefinitions<object>;

Expected behavior:

The type of X to be string as I have explicitly said it will be.

Actual behavior:

The type of X is string | number.

Playground Link:

http://www.typescriptlang.org/play/#src=type%20EventDefinitions%3CTEventPayload%20extends%20object%3E%20%3D%20%7B%0D%0A%20%20%20%20%5BeventName%3A%20string%5D%3A%20TEventPayload%3B%0D%0A%20%20%7D%3B%0D%0A%0D%0Atype%20X%20%3D%20keyof%20EventDefinitions%3Cobject%3E%3B

Related Issues:

Maybe this: #26470 ?

@RyanCavanaugh RyanCavanaugh added the Question An issue which isn't directly actionable in code label Sep 17, 2018
@RyanCavanaugh
Copy link
Member

In TypeScript, when a type can be indexed by string, it can also be indexed by number, so keyof is consistent by providing the legal key types for the provided operand.

@mikecann
Copy link
Author

@RyanCavanaugh oh okay :S Thanks for that, it was certainly unexpected behaviour for me. Is there a way to explicitly say its going to be a string?

@unional
Copy link
Contributor

unional commented Feb 13, 2019

On the other hand:

type R = Record<string, number>

type Y = keyof R // string

It caught me by surprise too. 🌷

@mikecann
Copy link
Author

@unional yep Record is the way to do it I think 👍

@naddeoa
Copy link

naddeoa commented Mar 4, 2019

Worth pointing out that the example in this issue is almost the exact example used in the docs here

https://www.typescriptlang.org/docs/handbook/advanced-types.html#index-types-and-string-index-signatures

That example claims that the keys will be of type string but they're actually of type string | number it seems.

https://www.typescriptlang.org/play/#src=interface%20Foo%3CT%3E%20%7B%0D%0A%20%20%20%20%5Bkey%3A%20string%5D%3A%20T%3B%0D%0A%7D%0D%0Alet%20keys%3A%20keyof%20Foo%3Cnumber%3E%3B%20%2F%2F%20string

Assuming I didn't miss something, I think those docs could use an update.

@mikecann
Copy link
Author

mikecann commented Mar 4, 2019

@naddeoa you are correct the docs are incorrect.. They say this:

interface Map<T> {
    [key: string]: T;
}
let keys: keyof Map<number>; // string
let value: Map<number>['foo']; // number

But its not true:

image

I would submit a PR for the docs but I dont think I understand the reason why this doesnt work enough to comment on it. IMO its counter-intuitive and we shouldnt need a Record to do this which is why I opened this issue in the first place but shrug

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

4 participants