question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Set esModuleInterop to "true" by default

See original GitHub issue

Search Terms

  • esModuleInterop

Suggestion

Change esModuleInterop from being an opt-in to instead be an opt-out, taking one step further towards deprecating the non-esModuleInterop mode and make esModuleInterop the only supported mode going forward (which has to be the long term goal).

Use Cases

When Typescript 2.7 introduced esModuleInterop almost 3 years ago it emphasized clearly that:

We highly recommend applying it both to new and existing projects.

esModuleInterop is also a recommended option to set in tsconfig.json and when one runs tsc --init it gets set to true automatically.

However, the fact that it still is opt-in makes that non-esModuleInterop mode is still very prevalent, which kind of works against the very problems it was meant to fix – as rather than having just the pre-esModuleInterop functionality, modules now have to try to make things work across both options – and on top of that increasingly have to work with TS-validated JS.

All in all, that causes problems: https://github.com/fastify/env-schema/pull/17

And is hard to wrap ones head around: https://github.com/fox1t/modules-playground

Even if one really tries: https://github.com/fox1t/modules-playground/pull/3

Checklist

My suggestion meets these guidelines:

  • This wouldn’t be a breaking change in existing TypeScript/JavaScript code
    • It would for all code which haven’t yet adopted esModuleInterop, but it would make it easier to get TypeScript and JavaScript code to stay compatible with one another
  • This wouldn’t change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
    • It would emit different JS for all code which haven’t yet adopted esModuleInterop, but it would make it easier to get TypeScript and JavaScript code to stay compatible with one another
  • This isn’t a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • This feature would agree with the rest of TypeScript’s Design Goals.
    • Apart from Do not cause substantial breaking changes from TypeScript 1.0.

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:2
  • Comments:10 (1 by maintainers)

github_iconTop GitHub Comments

3reactions
bmeckcommented, Mar 30, 2021

@voxpelli

My impression was that esModuleInterop was meant to increase compatibility?

It kind of does, but not enough to be completely compatible. Particularly how "default" works still tries to do some magic and things start to get incompatible because of it.

Given:

// ./entry.ts
import * as asNamespace from './dep.js';
import asDefault from './dep.js';

console.log({
  asDefault,
  asNamespace
});
// ./dep.js
module.exports = {
  __esModule: true,
  default: 'prop named default'
};

Compiling to CommonJS will result in the following outputs:

Node (after renaming .ts to .mjs):

$ node ./entry.mjs
{
  asDefault: { __esModule: true, default: 'prop named default' },
  asNamespace: [Module: null prototype] {
    __esModule: true,
    default: { __esModule: true, default: 'prop named default' }
  }
}

After TS:

$ node ./out/entry.js
{ asDefault: 'prop named default',
  asNamespace: { __esModule: true, default: 'prop named default' } }

Namely, even with esModuleInterop it tries to do some hoisting of the default property if __esModule:true exists that Node won’t ever do.

3reactions
bmeckcommented, Mar 17, 2021

I’m a bit wary of using esModuleInterop since how it interacts with node’s ESM implementation of default isn’t quite compatible. This leads to various conversations about what to do usually ending up with “don’t use default exports” as my go to response. Enabling it by default would remove some issues but it seems like a second migration would have to happen afterward if node compatibility was another configuration option.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Understanding esModuleInterop in tsconfig file - Stack Overflow
(Moment here does not have default export) If we set esModuleInterop to true, then line no 3, will give following error
Read more >
TSConfig Option: esModuleInterop - TypeScript
By default (with esModuleInterop false or not set) TypeScript treats CommonJS/AMD/UMD modules similar to ES6 modules. In doing this, there are two parts...
Read more >
Module can only be default-imported using esModuleInterop flag
The esModuleInterop option is set to false by default, which causes it to treat CommonJS modules similar to ES6 modules. This causes some...
Read more >
What is TypeScript esModuleInterop and why you should set it
In this lesson we look at the #TypeScript # ESModuleInterop compiler option. We discuss the reason why it exists and why you should...
Read more >
How To Use Modules in TypeScript | DigitalOcean
esModuleInterop to true in the tsconfig.json file. By default, this value is false . When this is set to true , the TypeScript...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found