-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
ES6 Modules default exports interop with CommonJS #2719
Comments
We considered that, but it only works if you also emit an Adding a bit more detail, Babel's compatibility mode generates a default export as an assignment to |
This behaviour is my blocker to adopt 1.5. export default class Foo {} commonjs users have to write below now with 1.5. (not for typescript, raw js for node.js) let Foo = require('./foo').default But this problem may be common.js/require spec's... *added * I wrote typescript as a part of my project, and provide common.js module to be required. |
@mizchi You're right, if you use |
@ahejlsberg yes, there is no clean way. I see your policy for interoperability with CommonJS. So, how about interop with other ES6 Module transpilers? // foo.ts (main of package "foo")
export default 'foo'; // An ES6 module to be compiled by Babel, Traceur, SystemJS
import foo from 'foo';
console.log(foo); // { default: 'foo' } instead of just 'foo' If TypeScript sets |
👍 |
4 similar comments
+1 |
+1 |
+1 |
+1 |
+1 |
I'm trying to redevelop RxJS in TypeScript, and this is a requirement, as RxJS needs to support CJS very cleanly. Any idea of where this sits as a priority? |
this is must-have feature. our team is really missing it and this is a stopper. |
@chicoxyzzy Thus far my solution is to transpile to es6, then use Babel to get to AMD and CJS. Finally Browserify to create a global, bundled file. It's a little wonky, but it works. (I'm authoring a library though) |
Just to clarify on the interop discussion - Babel's handling of making the default export the primary module.exports is a convenience unrelated to Babel's handling of CommonJS interop - they are orthogonal concerns. The handling of CommonJS interop is exactly the flag system though. |
@guybedford nonetheless, if you want CJS interop without having to add |
Must have feature. |
While evaluating TS for a new big project I am working on, we stumbled upon this issue which is a blocker. |
I'm not sure why everyone is +1:ing. Either everyone is TypeScript library owners or they think it solves the opposite problem. I'm actually more annoyed about the opposite problem. How to import a default export from CommonJS in ES6. I want to write everything using the ES6 module syntax and not having to resolve to Many libraries have a default exported function defined in CommonJS like below: module.exports = function() { ... } And the best solution is to use the old TS syntax to import; import module_ = require('./module'); Because you can't import it using ES6 module syntax. So my code base is filled with mixed module syntaxes. If we decided to emit the Then my code base can be a lot cleaner: import something from 'commonjs' |
Actually, In other words, there's more care being placed into the implementation than into how end users interact with modules. Why don't we just make it easy for the end user? It would be great to have a way to configure I don't see why this has to be a pain point. It would be so great to have it be configurable!
That might be only true in purely TypeScript environments. But you might know that TypeScript can compile to es2015 and leave es6 module statements alone. Will this cause another loader like webpack or babel to crash? If so then that's no good. However, if we can configure default imports to grab the exported objects of AMD or CommonJS modules in TS, then we can for example take advantage of Babel's interop in a following build step, and everything will just work. |
Hey all, as a newcomer to this thread, I am looking for "the answer" here. My thinking is that this has been resolved in favor of the askers, but I am not sure. I have a TS module that does this: export default {foo: 'bar'}; in my Node.js version 0.12 code, I have var x = require('ts-module').default; how exactly, can I avoid using the default property when using older versions of Node? in other words, I cannot do this: const {default as x} = require('ts-module'); because my library needs to support older versions of Node. It would be nice to know in simple terms what the resolution to this issue was. Thanks all. I know that AVA solved the problem this way https://github.com/avajs/ava/blob/master/lib/main.js like so: module.exports = runner.test;
// TypeScript imports the `default` property for
// an ES2015 default import (`import test from 'ava'`)
// See: https://github.com/Microsoft/TypeScript/issues/2242#issuecomment-83694181
module.exports.default = runner.test; but I am not sure if they generated that file with TS though... I am looking for the way to generate/declare that kind of code with TS |
The official solution is to use TypeScript's special syntax, for example: export = {foo: 'bar'}; then in your old Node code you can do var x = require('ts-module'); without However, this has serious limitations when trying to interop with other module formats or module bundlers because (for example) TypeScript compiles those statements to nothing (they just disappear), and then you'll get errors in (for example) Webpack. That special format basically only works for app authors, not for library authors, and not for app authors doing more complex things like needing intermediate module processing steps (tools like Babel, Webpack, etc, don't understand TypeScript's special |
Basically the downside of ES6 is that it isn't designed to be backwards compatible with previous module formats, and there isn't any standard on how to transpile ES6 modules for older formats. |
thanks, yeah that solution unfortunately won't work for me, because I am exporting another TS interface from the same file, so TS will complain when I use Maybe there is no solution to this one at the moment :( my personal solution is to do this: const x = {foo:'bar'}
x.default = x;
module.exports = x; not my fav thing in the world LOL |
Have the similar problem. I'm writing typedef file for an existing module. The module is CommonJS that exports a function ( Alongside with it I also have to define and export some interfaces. So the |
@emirotin If you want to export types, you should consider placing them in a merged namespace. Here is an example export = configure;
function configure(options: configure.Options) {
return { ...options, key: 'value' };
}
namespace configure {
export interface Options {
pluginName: string;
inject?: true;
}
} example-consumer.ts import * as configure from './configure'; // or import = require ..., or import configure from...
const options: configure.Options = {
pluginName: 'abstraction helper gizmo'
};
configure(options); |
Right @aluanhaddad thanks a lot, have just discovered it 15 minutes ago :) |
@aluanhaddad Thanks for solution! What if I need to write a module that exports an object, and exports some interfaces (for ts dependencies)? like: export interface Option{
key1:string
}
export = {
fun(option:Option) {
// do stuff
}
} Some annoying limitations:
Thanks for any idea! |
You just need to name the exported object: const exportObject = {
fun(option:exportObject.Option) {
// do stuff
}
}
export = exportObject;
namespace exportObject {
export interface Option{
key1: string
}
} But of course when you use the top level export, it exports an object anyways. So why wouldn't you do this? export interface Option{
key1:string
}
export function fun(option:Option) {
// do stuff
} As that would have exactly the same shape of an export as what you originally had. |
@kitsonk My current approach is to just export this instance as a named object ( Thanks a lot! |
* Add middle click tab closing (#2069) by adding a onMouseDown directive to both tab file icon and tab name and checking the resulting React.MouseEvent for a middle click * Fix unused imports and whitespace in Tabs ui test (#2069) * Update Tabs component test snapshot (#2069) * Fix Tabs ui test to correctly retrieve children (#2069) * Differentiate between single und multiple tabs in test (#2069) * Use mousedown event for tab selection and closing (#2069) by middle clicking and let the tab itself handle the logic for it by checking React.MouseEvent.button value * Update classnames dependency to lastest master branch and write own @types module declaration so that it can be used in testing nstead of using a mock. The mock does not suffice as the way the actual module previously had to be imported was "import * as classNames" where classNames was the actual function. It is not possible to build a module in typescript/es6 imports, which will directly return a function in the same way the dependency did in commonjs module syntax. Instead when defining a function to be returned as default export it is returned as an Object like this "{ default: [Function] }", which is correctly resolved when importing with "import classNames from 'classnames'". This only previously worked in production as webpacks ts-loader, handles this issue, whereas when testing the sources are only compiled with tsc. There is an update to the classnames dependency on the current master, but there hasn't been a release since 2006. So options were to setup webpack for tests as well or add updated classnames dependency which sets a "default" value on its commonjs exports. Links for reference: JedWatson/classnames#152 JedWatson/classnames#106 DefinitelyTyped/DefinitelyTyped#25206 microsoft/TypeScript#2719 * Fix tab click onMouseDown callback * Test tab clicks to select/close trigger callbacks * Mock child react components directly to test smaller unit * Reset calls to callback mocks in each test case * Add tests for tabs interaction with FileIcon/Sneakable
CommonJS cannot requires a package transpiled from TypeScript ES6 Modules using default export well.
TS 1.5-alpha transpiles default exports:
to:
So users of this package
foo
need to add.default
property torequire()
.It's a little messy...
Babel resolves this issue.
It sounds pretty nice and actually works for me.
The text was updated successfully, but these errors were encountered: