Skip to content

Always treat .d.*.ts files as commonjs-format modules for the purposes of import interop #59622

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

weswigham
Copy link
Member

Fixes #57229

The way allowSyntheticDefaultImports/esModuleInterop and module: nodenext's "type": "module" detection interplay in the context of .d.*.ts files right now is... confusing. Since they are .ts files, they do currently get assigned a package.json-type-dependent module kind, which determines if the module is made available as a default or not on an esm import, and if a cjs file can import it at all, and furthermore we have heuristics involving the presence of a default in the declaration file which can then disable the synthetic default creation for interop'd imports (import statements in cjs format files under module: nodenext).

This menagerie of behaviors means that to write a declaration file for a json file similar to ["foo", "bar"], so is no single way to write it that works for all callers, in all package type contexts, even though json imports (or any non-js import) are not package type dependent.

On investigation, I find this state of affairs confusing.

This PR changes how we interpret .d.*.ts file module formats to always be cjs-like. This means the correct way to write the declaration file for ["foo", "bar"] is always

declare const _export: ["foo", "bar"];
export = _export;

and registers as importable by all import and require constructs in all package type contexts.

@weswigham weswigham added Breaking Change Would introduce errors in existing code Domain: ES Modules The issue relates to import/export style module behavior labels Aug 13, 2024
@typescript-bot typescript-bot added Author: Team For Milestone Bug PRs that fix a bug with a specific milestone labels Aug 13, 2024
@weswigham weswigham requested a review from andrewbranch August 13, 2024 22:19
@andrewbranch
Copy link
Member

With --allowJsonModule, we leave the impliedNodeFormat of JSON source files as undefined. It feels like that might be the right move here? I expect the results to be the same, but it would leave us the ability to futz with things later if needed. I'm imagining a scenario where, say, a bundler/runtime loader converts a CSS file to an ES module, and the declaration file for it looks like

export const class1: string;
export const class2: string;

With this change, it becomes legal to import that file like

import css from "./styles.css";

when in fact no default import will be synthesized by the runtime since the loader exposed it as a real module. If we had any precedent for doing something like this, maybe it would be nice to assign the module kind based on module syntax (CJS for export =, ESM otherwise).

I think this will work alright and is better than the status quo, but I can see us needing to revisit it if some third-party framework begins making really heavy use of .d.*.ts files or something.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Author: Team Breaking Change Would introduce errors in existing code Domain: ES Modules The issue relates to import/export style module behavior For Milestone Bug PRs that fix a bug with a specific milestone
Projects
Status: Not started
Development

Successfully merging this pull request may close these issues.

.d.json.ts file (allowArbitraryExtensions) not working correctly when importing from ESM file with node16/nodenext module setting
3 participants