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

verbatimModuleSyntax + import of ambient const enum missing error #48040

Open
jablko opened this issue Feb 25, 2022 · 5 comments
Open

verbatimModuleSyntax + import of ambient const enum missing error #48040

jablko opened this issue Feb 25, 2022 · 5 comments
Assignees
Labels
Bug A bug in TypeScript Has Repro This issue has compiler-backed repros: https://aka.ms/ts-repros

Comments

@jablko
Copy link
Contributor

jablko commented Feb 25, 2022

Bug Report

preserveValueImports doesn't error when you import an ambient const enum with isolatedModules on. Instead you get an error at runtime.

🩹 Proposed Solution

If the named import were a type vs. an ambient const enum, you'd get a compile-time error instead.

#47817 raises that error on ambient const enums, by changing its predicate to include ambient const enums.

🔍 Search Terms

preserveValueImports ambient const enum

🕗 Version & Regression Information

4.5.0-dev.20210909 - 4.7.0-dev.20220225

⏯️ Playground Link

Workbench Repro

🧑‍💻 Code

// @preserveValueImports
// @isolatedModules
import { RoundingMode } from "big.js";

// @filename: node_modules/big.js/index.d.ts
export const enum RoundingMode {}

🙁 Actual Behavior

Runtime error:

import { RoundingMode } from "big.js";
         ^^^^^^^^^^^^
SyntaxError: Named export 'RoundingMode' not found. The requested module 'big.js' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from 'big.js';
const { RoundingMode } = pkg;

🙂 Expected Behavior

Compile-time error (with #47817):

index.ts:1:10 - error TS1446: 'RoundingMode' resolves to a type-only declaration and must be imported using a type-only import when 'preserveValueImports' and 'isolatedModules' are both enabled.

1 import { RoundingMode } from "big.js";
           ~~~~~~~~~~~~
@RyanCavanaugh
Copy link
Member

@andrewbranch what's your take? The linked PR has some additional context

@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label Feb 26, 2022
@andrewbranch
Copy link
Member

I think differentiating on ambient is highly problematic, though I understand why it’s tempting to do so. If we weren’t talking about the enigma of const enums specifically, it would be super wrong to consider ambience. Ambient declarations are assumed to exist in the same way non-ambient declarations exist, just in a location that the compiler doesn’t have direct knowledge of. Type-checking behavior should generally not be impacted by ambience; otherwise you’ll get different behavior between consuming .ts files and consuming the .d.ts outputs of those same files. Even more confusingly, in project references, you’ll get different behavior between the CLI and the editor, because the former uses .d.ts files for referenced projects while the latter defaults to using .ts files.

The story changes slightly when talking about const enums, because when you tsc -d a const enum declaration, we emit an (ambient) const enum declaration in the .d.ts file, and whether there is an existing runtime value can be toggled based on other compiler options. So given an ambient const enum declaration, we really have no idea whether or not a runtime equivalent exists. (This was the basis for my proposal to introduce some kind of syntactic marker in .d.ts files for const enums that indicates whether there is a real runtime equivalent, which was rejected because it appeared to make enums more complex. I think this issue demonstrates that such a marker doesn’t expand the bits of information we care about with enums, but rather codifies a fairly fundamental one—whether or not there is any runtime representation—that we already try to consider but fail to do so accurately.) On the other hand, if the compiler sees a non-ambient const enum declaration, it can know whether or not there will be a runtime equivalent, because the current compilation will be responsible for producing it. So I think in many ways the proposal here makes sense:

  • ambient const enum → don’t know if reified → error always
  • non-ambient const enum → detect if reified → error if not

It’s really the project references scenario that makes me uncomfortable with this. Without other changes, you will be unable to consume your own preserved const enums from a referenced project with --isolatedModules --preserveValueImports, but this error will not show up in the editor. We could check if the declaration came from a project reference redirect, and check the compiler options of the referenced project (which would require an additional API added to TypeCheckerHost) to see if it would have been preserved. But this too may not be quite right, as the const enum declaration could have been hand-written with declare in the input file, where by this complicated logic we arguably should error (???) since we again are unsure whether a runtime equivalent exists.

Summary:

  • I agree the current state errs on being too permissive; it does not catch a class of problematic imports that I would like to catch.
  • This proposal is perhaps the best we can do in terms of classifying which imports will work or fail at runtime without adding more information to declaration emit of const enums going forward, but the fact that project references will behave differently in the CLI and in the editor seems like a blocker to me.
  • The inconsistency between the CLI and editor for project references can perhaps be mitigated with some additional checker logic, but this logic will be imperfect and does not already exist anywhere in the checker.

@jablko
Copy link
Contributor Author

jablko commented Mar 1, 2022

@andrewbranch Thanks!

In other words this here proposal doesn't introduce any new issues? For the existing issue you mention, there's a solution without adding more information to declaration emit of const enums ... but it has problems with inlining referenced projects' enums? ... but maybe that can be worked around? It's a separate issue?

@andrewbranch andrewbranch changed the title preserveValueImports + ambient const enum emits error verbatimModuleSyntax + import of ambient const enum missing error May 23, 2024
@typescript-bot typescript-bot added the Has Repro This issue has compiler-backed repros: https://aka.ms/ts-repros label May 23, 2024
@andrewbranch
Copy link
Member

This is still an issue for verbatimModuleSyntax, but the project references discrepancy I was concerned about in earlier messages was handled recently in #57914. I think we should go ahead and do this for 5.6. It doesn’t make much sense to error on the use sites but not on the import that will be preserved. Under verbatimModuleSyntax, we should probably make the error only appear on the import, not on the use sites. That way, a single ts-ignore can be used to escape situations where we don’t know that an ambient const enum was reified with preserveConstEnums.

@andrewbranch andrewbranch added this to the TypeScript 5.6.0 milestone May 23, 2024
@andrewbranch andrewbranch added Bug A bug in TypeScript and removed Needs Investigation This issue needs a team member to investigate its status. labels May 23, 2024
@typescript-bot
Copy link
Collaborator

typescript-bot commented May 24, 2024

👋 Hi, I'm the Repro bot. I can help narrow down and track compiler bugs across releases! This comment reflects the current state of the repro in the issue body running against the nightly TypeScript.


Issue body code block by @jablko

‼️ Exception: Error - error TS5102: Option 'preserveValueImports' has been removed. Please remove it from your configuration. Use 'verbatimModuleSyntax' instead.

Error: error TS5102: Option 'preserveValueImports' has been removed. Please remove it from your configuration.
  Use 'verbatimModuleSyntax' instead.

    at Object.createVirtualTypeScriptEnvironment (/home/runner/work/_actions/microsoft/TypeScript-Twoslash-Repro-Action/8680b5b290d48a7badbc7ba65971d526c61b86b8/dist/index.js:8128:11)
    at twoslasher (/home/runner/work/_actions/microsoft/TypeScript-Twoslash-Repro-Action/8680b5b290d48a7badbc7ba65971d526c61b86b8/dist/index.js:7618:17)
    at /home/runner/work/_actions/microsoft/TypeScript-Twoslash-Repro-Action/8680b5b290d48a7badbc7ba65971d526c61b86b8/dist/index.js:439:44
    at runTwoslashRequests (/home/runner/work/_actions/microsoft/TypeScript-Twoslash-Repro-Action/8680b5b290d48a7badbc7ba65971d526c61b86b8/dist/index.js:406:56)
    at run (/home/runner/work/_actions/microsoft/TypeScript-Twoslash-Repro-Action/8680b5b290d48a7badbc7ba65971d526c61b86b8/dist/index.js:20096:75)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

Historical Information
Version Reproduction Outputs Time
5.0.2, 5.1.3, 5.2.2, 5.3.2, 5.4.2

‼️ Exception: Error - error TS5101: Option 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify compilerOption '"ignoreDeprecations": "5.0"' to silence this error. Use 'verbatimModuleSyntax' instead.

Error: error TS5101: Option 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify compilerOption '"ignoreDeprecations": "5.0"' to silence this error.
  Use 'verbatimModuleSyntax' instead.

    at Object.createVirtualTypeScriptEnvironment (/home/runner/work/_actions/microsoft/TypeScript-Twoslash-Repro-Action/8680b5b290d48a7badbc7ba65971d526c61b86b8/dist/index.js:8128:11)
    at twoslasher (/home/runner/work/_actions/microsoft/TypeScript-Twoslash-Repro-Action/8680b5b290d48a7badbc7ba65971d526c61b86b8/dist/index.js:7618:17)
    at /home/runner/work/_actions/microsoft/TypeScript-Twoslash-Repro-Action/8680b5b290d48a7badbc7ba65971d526c61b86b8/dist/index.js:439:44
    at /home/runner/work/_actions/microsoft/TypeScript-Twoslash-Repro-Action/8680b5b290d48a7badbc7ba65971d526c61b86b8/dist/index.js:427:51
    at Array.map (<anonymous>)
    at runTwoSlashOnOlderVersions (/home/runner/work/_actions/microsoft/TypeScript-Twoslash-Repro-Action/8680b5b290d48a7badbc7ba65971d526c61b86b8/dist/index.js:425:23)
    at runTwoslashRequests (/home/runner/work/_actions/microsoft/TypeScript-Twoslash-Repro-Action/8680b5b290d48a7badbc7ba65971d526c61b86b8/dist/index.js:408:66)
    at run (/home/runner/work/_actions/microsoft/TypeScript-Twoslash-Repro-Action/8680b5b290d48a7badbc7ba65971d526c61b86b8/dist/index.js:20096:75)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)

⚠️ Way slower

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Has Repro This issue has compiler-backed repros: https://aka.ms/ts-repros
Projects
None yet
Development

No branches or pull requests

4 participants