Skip to content

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