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

Change isolatedModules to allow const enum declaration and disallow access #28465

Conversation

alangpierce
Copy link
Contributor

Fixes #20703 with solution suggested in #20703 (comment)

Previously, --isolatedModules gave an error for any ambient const enum, which
meant that some third-party libraries would always give errors even if the
ambient const enums they declare were never used. Now, we only give an error
when an ambient const enum is referenced, which allows such libraries to still
be used as long as the const enums are never accessed.

Some nuances:

  • As before, the error is only surfaced for ambient const enums. With
    non-ambient const enums, we know that an isolatedModules build will emit the
    enum and produce a plain reference rather than inlining the constant, so
    everything will still work.
  • I originally planned to do this check in the code path that inlines the
    constant, but that code is only exercised at emit time, so, for example, the
    TS language service wasn't giving an error in my editor. Instead, I do the
    check at typecheck time next to another const-enum-related check.
  • This can be a breaking change when using skipLibCheck because the error is
    typically moved from a .d.ts file to a .ts file.

Testing done:
I ran this TS build on a large project of mine that previously had disabled
isolatedModules so I could use the chalk library. With isolatedModules
enabled, there was no longer an error in the chalk typedefs, and a reference to
the Level const enum produced an error in my editor.

…ccess

Fixes microsoft#20703 with solution suggested in microsoft#20703 (comment)

Previously, `--isolatedModules` gave an error for any ambient const enum, which
meant that some third-party libraries would always give errors even if the
ambient const enums they declare were never used. Now, we only give an error
when an ambient const enum is referenced, which allows such libraries to still
be used as long as the const enums are never accessed.

Some nuances:
* As before, the error is only surfaced for *ambient* const enums. With
  non-ambient const enums, we know that an `isolatedModules` build will emit the
  enum and produce a plain reference rather than inlining the constant, so
  everything will still work.
* I originally planned to do this check in the code path that inlines the
  constant, but that code is only exercised at emit time, so, for example, the
  TS language service wasn't giving an error in my editor. Instead, I do the
  check at typecheck time next to another const-enum-related check.
* This can be a breaking change when using `skipLibCheck` because the error is
  typically moved from a .d.ts file to a .ts file.

Testing done:
I ran this TS build on a large project of mine that previously had disabled
`isolatedModules` so I could use the `chalk` library. With `isolatedModules`
enabled, there was no longer an error in the chalk typedefs, and a reference to
the `Level` const enum produced an error in my editor.
Copy link
Member

@RyanCavanaugh RyanCavanaugh left a comment

Choose a reason for hiding this comment

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

LGTM, just one thing - can you please address the merge conflict in diagnosticMessages.json? Thanks!

@RyanCavanaugh RyanCavanaugh self-assigned this Jan 24, 2019
export var y = E.X;
Copy link
Member

@sheetalkamat sheetalkamat Jan 24, 2019

Choose a reason for hiding this comment

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

Should this error be any other file than the declaration of const enum file?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The intention with this change is for the error to be on the access, not on the declaration, so in practice it could be in a completely different file than the const enum declaration. In a typical case, I might import the chalk library, which shouldn't error, but any attempt to use the Level enum should error.

I could see an argument for putting an additional error on the const enum (like before), but the point of this change is that simply declaring a const enum is not an error anymore; the error is if you try to use it.

Copy link
Member

Choose a reason for hiding this comment

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

Yes the error is on access but declaring const enum a {} and using a in module1 shouldn't cause error. It should cause when accessing in module2...n instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Got it. I just tested it a bit more, and I believe the error still makes sense even within the same file. To be clear, this only happens with isolatedModules enabled and only happens for ambient const enums (the declare is necessary in the code above example).

From my testing, it looks like with isolatedModules enabled, const enums are always compiled as plain enums and const enum accesses are always compiled as plain enum accesses, even when the const enum is in the same file. That means that in this code snippet, the first line is erased (since it's a declare) and the second line is compiled as-is as export var y = E.X. With isolatedModules, TypeScript will not inline the constant even within the same file, so this code would crash at runtime (because E doesn't exist) even though it would work at runtime without isolatedModules. So I think it's fair for TS to error here.

It certainly seems like a reasonable future improvement to implement inlining within the same file even when isolatedModules is on. In that case, this error could be limited to cross-file accesses, but for now, even same-file ambient const enum accesses need to be errors. This would also require the Babel implementation to implement same-file constant inlining.

@alangpierce
Copy link
Contributor Author

@RyanCavanaugh

can you please address the merge conflict in diagnosticMessages.json

Done! Thanks for taking a look.

@RyanCavanaugh
Copy link
Member

Sorry, we're trying to merge a ton of PRs right now and it looks like there's one in checker.ts now

@alangpierce alangpierce force-pushed the enforce-const-enum-access-for-isolatedmodules branch from 2ba84d9 to 942b020 Compare February 2, 2019 02:53
@alangpierce
Copy link
Contributor Author

@RyanCavanaugh Ok, just updated to resolve the conflict!

@RyanCavanaugh RyanCavanaugh merged commit eed9db5 into microsoft:master Feb 6, 2019
@alangpierce alangpierce deleted the enforce-const-enum-access-for-isolatedmodules branch February 6, 2019 15:26
@alangpierce
Copy link
Contributor Author

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants