diff --git a/packages/documentation/copy/en/modules-reference/appendices/ESM-CJS-Interop.md b/packages/documentation/copy/en/modules-reference/appendices/ESM-CJS-Interop.md index 5d9ba44e6f54..d086e3a184f6 100644 --- a/packages/documentation/copy/en/modules-reference/appendices/ESM-CJS-Interop.md +++ b/packages/documentation/copy/en/modules-reference/appendices/ESM-CJS-Interop.md @@ -313,7 +313,35 @@ As we’ve seen, there is no seamless migration path from transpiled modules to ### Library code needs special considerations -Libraries (that ship declaration files) should take extra care to ensure the types they write are error-free under a wide range of compiler options. For example, it’s possible to write one interface that extends another in such a way that it only compiles successfully when `strictNullChecks` is disabled. If a library were to publish types like that, it would force all their users to disable `strictNullChecks` too. `esModuleInterop` can allow type declarations to contain similarly “infectious” default imports: +Libraries that ship as CommonJS should avoid using default exports, since the way those transpiled exports can be accessed varies between different tools and runtimes, and some of those ways will look confusing to users. A default export, transpiled to CommonJS by `tsc`, is accessible in Node.js as the default property of a default import: + +```js +import pkg from "pkg"; +pkg.default(); +``` + +in most bundlers or transpiled ESM as the default import itself: + +```js +import pkg from "pkg"; +pkg(); +``` + +and in vanilla CommonJS as the default property of a `require` call: + +```js +const pkg = require("pkg"); +pkg.default(); +``` + +Users will detect a misconfigured module smell if they have to access the `.default` property of a default import, and if they’re trying to write code that will run both in Node.js and a bundler, they might be stuck. Some third-party TypeScript transpilers expose options that change the way default exports are emitted to mitigate this difference, but they don’t produce their own declaration (`.d.ts`) files, so that creates a mismatch between the runtime behavior and the type checking, further confusing and frustrating users. Instead of using default exports, libraries that need to ship as CommonJS should use `export =` for modules that have a single main export, or named exports for modules that have multiple exports: + +```diff +- export default function doSomething() { /* ... */ } ++ export = function doSomething() { /* ... */ } +``` + +Libraries (that ship declaration files) should also take extra care to ensure the types they write are error-free under a wide range of compiler options. For example, it’s possible to write one interface that extends another in such a way that it only compiles successfully when `strictNullChecks` is disabled. If a library were to publish types like that, it would force all their users to disable `strictNullChecks` too. `esModuleInterop` can allow type declarations to contain similarly “infectious” default imports: ```ts // @Filename: /node_modules/dependency/index.d.ts