-
Notifications
You must be signed in to change notification settings - Fork 90
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
Generate index.d.mts
and index.d.cts
#238
Comments
Can confirm this. Calling from cjs context a package with following package.json: "type": "module",
"exports": {
"./generateMessageId": {
"import": {
"types": "./dist/generateMessageId.d.ts",
"default": "./dist/generateMessageId.mjs"
},
"require": {
"types": "./dist/generateMessageId.d.ts",
"default": "./dist/generateMessageId.cjs"
}
},
}, Will result in
As you see even explicit "./generateMessageId": {
"import": {
"types": "./dist/generateMessageId.d.mts",
"default": "./dist/generateMessageId.mjs"
},
"require": {
"types": "./dist/generateMessageId.d.cts",
"default": "./dist/generateMessageId.cjs"
}
}, If in dist folder would be a file without concrete extension, such as just Also, what should be considered. When stubbing, d.ts file for ESM should be produced with extension in imports, otherwise it doesn't work: // stub in /dist
export * from "/Users/tim/projects/js-lingui/packages/message-utils/src/generateMessageId"; // <-- doesn't work
export * from "/Users/tim/projects/js-lingui/packages/message-utils/src/generateMessageId.ts"; // <-- work |
One thing to also consider is that
|
@karlhorky I assume lots of tools/websites do look at that field to determine whether a package has types or not. |
It seems currently we can only get ESM types with Lines 182 to 185 in f7e614b
|
Also related: microsoft/TypeScript#50466 |
Generating proper cjs typings might be tricky. It will go smooth only if you don't have a The problem is Rollup depending on configuration / input would generate different exports semantics for // input
export default class Foo {}
// output
class Foo {}
module.exports = Foo If you have named + default exports or if you set // input
export default class Foo {}
// output
class Foo {}
module.exports.default = Foo This led to the different typings in cjs: // d.cts
// module.exports = Foo
// ↓ ↓ ↓ ↓ ↓ ↓
exports = Foo;
// module.exports.default = Foo
// ↓ ↓ ↓ ↓ ↓ ↓
export default Foo; So as long you don't have any Unfortunately, One of the solutions might be fixing Rollup's |
Hi Pooya, more context here https://twitter.com/atcb/status/1634653474041503744?s=20 I'm so confused 😖, as far as I understand from this tweet proper package.json should look like this? {
"type": "module", // not required, it's based on environments, or lib author interest
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.cjs",
},
"./another": {
"import": "./dist/another.mjs",
"require": "./dist/another.cjs",
},
"main": "./dist/index.cjs", // for pre node <16?
"module": "./dist/index.mjs", // for pre node <16?
"types": "./dist/index.d.[mts|cts|ts]" // for pre node <16? but which one
}
} Or like this "exports": {
".": {
"import": {
"types": "./types/index.d.mts",
"default": "./dist/index.mjs"
},
"require": {
"types": "./types/index.d.cts",
"default": "./dist/index.cjs"
}
},
"./another": {
"import": {
"types": "./types/another.d.mts",
"default": "./dist/another.mjs"
},
"require": {
"types": "./types/another.d.cts",
"default": "./dist/another.cjs"
}
}
} |
cc @andrewbranch, since you've been mentioned a few times here |
@sadeghbarati the twitter thread you referenced is very helpful. Regarding your questions: {
"main": "./dist/index.cjs", // for pre node <16?
"module": "./dist/index.mjs", // for pre node <16?
"types": "./dist/index.d.[mts|cts|ts]" // for pre node <16? but which one
}
If summarize and simplify a lot, if you don't have If you do have a @pi0 another big thing to consider. @andrewbranch made a great tool which could be incorporated as part of unbuild to validate typings https://github.com/arethetypeswrong/arethetypeswrong.github.io on a validate step. |
Thanks for all input, references, and ideas. I think going forward with a simple copy/pasted version of I understand there are different opinions on what we should recommend for a standard
Regarding top-level fields other than
|
Note that renaming/copying declaration files is a fundamentally unchecked operation. It might result in a valid output, but it might not. I don’t know enough about what unbuild is doing to recommend something concrete. But basically every build system for packages I’ve ever seen does something like this:
Now suppose you copy/rename/transform the type declarations from one output to another. Even if, by total coincidence, the result is a correct representation of the JS it claims to type, nobody ever checked if that JS was type-safe. The problem is that |
So we should create both |
Trying to get a few of my libraries built with unbuild to appear as valid with https://github.com/arethetypeswrong/arethetypeswrong.github.io Am I correct to assume that we want is for unbuild to support the following export map / fields ? :
according to @thekip we would have issues with packages that have a default export ... For the meantime I wrote a tiny script that I run after unbuild : import { copyFileSync } from "node:fs"
import { resolve } from "node:path"
import { fileURLToPath } from "node:url"
import fg from "fast-glob"
const dir = fileURLToPath(new URL("..", import.meta.url))
const dts = await fg(resolve(dir, "dist/**/*.d.ts"))
// Create MTS and CTS files
const dmts = dts.map(f => copyFileSync(f, f.replace(/\.d\.ts$/, ".d.mts")))
const dcts = dts.map(f => copyFileSync(f, f.replace(/\.d\.ts$/, ".d.cts")))
console.log(`Copied ${dmts.length} files from \`*.d.ts\` to \`*.d.mts\``)
console.log(`Copied ${dcts.length} files from \`*.d.ts\` to \`*.d.cts\``) And that does the trick. |
@pi0 Hi, I create a PR to fix it. |
Just discovered another tool that support this, linking here for reference |
The recent lingui#1742 explicitly exports TypeScript type definitions from package.json: ```json "exports": { ".": { "require": { "types": "./dist/index.d.ts", "default": "./dist/index.cjs" }, "import": { "types": "./dist/index.d.ts", "default": "./dist/index.mjs" } }, "./package.json": "./package.json" }, ``` Unfortunately, [as documented in the TypeScript Handbook][handbook], CommonJS (`require`) and ESM (`import`) module versions cannot share the same index.d.ts file: > It’s important to note that the CommonJS entrypoint and the ES module entrypoint each needs its own declaration file, even if the contents are the same between them. Every declaration file is interpreted either as a CommonJS module or as an ES module, based on its file extension and the "type" field of the package.json, and this detected module kind must match the module kind that Node will detect for the corresponding JavaScript file for type checking to be correct. Attempting to use a single .d.ts file to type both an ES module entrypoint and a CommonJS entrypoint will cause TypeScript to think only one of those entrypoints exists, causing compiler errors for users of the package. I am seeing the compiler errors that this documentation warns of. This issue appears to have been recently fixed in the unbuild build tool that js-lingui depends upon (see issue unjs/unbuild#238 and fix unjs/unbuild#273), and that fix was released in [unbuild 2.0.0-rc0]. This fix for detect-locale, therefore, is to upgrade to unbuild 2.0.0, and use the separate .d.cts and .d.mts type declaration files it outputs. **Note:** This moves detect-locale onto a newer major version of unbuild than the other packages in this monorepo. It may be preferred to upgrade them all, but I am not familiar enough with the other packages to do this quickly. [handbook]: https://www.typescriptlang.org/docs/handbook/esm-node.html#packagejson-exports-imports-and-self-referencing [unbuild 2.0.0-rc0]: https://github.com/unjs/unbuild/blob/main/CHANGELOG.md#v200-rc0
References: #226
The text was updated successfully, but these errors were encountered: