Skip to content

Implicit index signatures for enum object types #31687

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

Merged
merged 6 commits into from
Jun 2, 2019

Conversation

ahejlsberg
Copy link
Member

@ahejlsberg ahejlsberg commented May 31, 2019

Types representing object literals or modules have inferable index signatures because their exact set of properties is known. This PR implements the same behavior for types representing enum objects since these also have exact and close ended sets of properties.

  • The enum object type of an enum with at least one numerically valued member has an implicit string index signature of type string | X, where X is a union of the types of all numerically valued members, and an implicit numeric index signature of type string.

  • The enum object type of an enum with only string valued members has an implicit string index signature of type string and no implicit numeric index signature.

In the above, X reflects the reverse mapping from strings to numeric enum values included in the generated code that initializes the enum object.

Fixes #30977 (to the extent we can fix it).

@ahejlsberg
Copy link
Member Author

@typescript-bot run dt
@typescript-bot test this

@typescript-bot
Copy link
Collaborator

typescript-bot commented May 31, 2019

Heya @ahejlsberg, I've started to run the extended test suite on this PR at bb15df3. You can monitor the build here. It should now contribute to this PR's status checks.

@typescript-bot
Copy link
Collaborator

typescript-bot commented May 31, 2019

Heya @ahejlsberg, I've started to run the parallelized Definitely Typed test suite on this PR at bb15df3. You can monitor the build here. It should now contribute to this PR's status checks.

const v2 = getStringIndexValue(E2);
const v3 = getStringIndexValue(E3);
const v4 = getNumberIndexValue(E1);
const v5 = getNumberIndexValue(E2);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this unknown and not an error? (Is it just because inference fails and "a thing with an inferrable index" is assignable to a {[x: number]: unknown}?) I'd think that yeah, E2 has an inferrable index type, sure, but we know that it has no numbers in it at all. But, from the stance that the number index signature (were it present in the type) would need to be assignable to the string index, this'd need to be E2.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because we infer nothing for T in the call to getNumberIndexValue. Keep in mind we're not doing an assignment here, we're just doing inference.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, we are doing an assignment - we're saying that a {[x: string]: E2} is assignable to a {[x: number]: unknown}. I guess the output type here just irks me a tad - it could only possibly be an E2 or keyof typeof E2, rather than an unknown.

Like, if I write enum StrNum { Zero = "0", One = "1" }, indexing by 0 or 1 is gunna get me Zero or One, likewise if I write enum NumStr { "0" = "Zero", "1" = "One" }, indexing by Zero or One is gunna get me "0" or "1".

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, indexing your StrNum by 0 or 1 is going to get you undefined (there's no reverse mapping for string valued members), and NumStr is an error because members can't have numeric names.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyway, the unknown type is consistent with what we infer for object literal types that have no numerically named members. In some sense it would be more consistent to return undefined since that's what you're going to get, but that really is an orthogonal issue.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's no reverse mapping for string valued member

I always forget about that.

Anyway, the unknown type is consistent with what we infer for object literal types that have no numerically named members

Oh, ick. Ok.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Breaking Change Would introduce errors in existing code
Projects
None yet
4 participants