Skip to content

Commit eaa8205

Browse files
authored
Add tip about avoiding default exports in CJS libraries (microsoft#3085)
1 parent a5c9c01 commit eaa8205

File tree

1 file changed

+29
-1
lines changed

1 file changed

+29
-1
lines changed

packages/documentation/copy/en/modules-reference/appendices/ESM-CJS-Interop.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,35 @@ As we’ve seen, there is no seamless migration path from transpiled modules to
313313

314314
### Library code needs special considerations
315315

316-
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:
316+
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:
317+
318+
```js
319+
import pkg from "pkg";
320+
pkg.default();
321+
```
322+
323+
in most bundlers or transpiled ESM as the default import itself:
324+
325+
```js
326+
import pkg from "pkg";
327+
pkg();
328+
```
329+
330+
and in vanilla CommonJS as the default property of a `require` call:
331+
332+
```js
333+
const pkg = require("pkg");
334+
pkg.default();
335+
```
336+
337+
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:
338+
339+
```diff
340+
- export default function doSomething() { /* ... */ }
341+
+ export = function doSomething() { /* ... */ }
342+
```
343+
344+
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:
317345

318346
```ts
319347
// @Filename: /node_modules/dependency/index.d.ts

0 commit comments

Comments
 (0)