Typescript: import default problem with target es5 and jsx

Created on 22 Sep 2016  路  5Comments  路  Source: microsoft/TypeScript

TypeScript Version: 2.0.2

Code
I've set up a github repository which shows the error

$ git clone https://github.com/aanno/connect-rxjs-to-react.git
$ git checkout ts2-with-babel
$ npm install
$ npm run-script start:dev

It basically boils down to the following. When I use tsc to target es6 und use babel to transform es6 to es5 the following is _working_:

import React, { createElement } from "react";
import ReactDOM, { render } from "react-dom";
import { RxStateProvider, createState } from "./state/RxState.js";
import App from "./components/App.jsx";
import reducer$ from "./reducers";

render(
  <RxStateProvider state$={createState(reducer$)}>
    <App />
  </RxStateProvider>,
  document.getElementById("root"),
);

However when I _only_ use tsc to target es5 directly:

$ git checkout ts2-without-babel
$ npm install
$ npm run-script start:dev

I encounter the following error (chrome development console):

main.tsx?550e:9Uncaught TypeError: Cannot read property 'createElement' of undefined
  (anonymous function) @ main.tsx?550e:9

It is because tsc transpiles the above code to the following:

"use strict";
var react_1 = require("react");
var react_dom_1 = require("react-dom");
var RxState_js_1 = require("./state/RxState.js");
var App_jsx_1 = require("./components/App.jsx");
var reducers_1 = require("./reducers");
react_dom_1.render(react_1.default.createElement(RxState_js_1.RxStateProvider, {"state$": RxState_js_1.createState(reducers_1.default)}, 
    react_1.default.createElement(App_jsx_1.default, null)
), document.getElementById("root"));

If I manually change the code like below, _the problem is gone_ (i.e. the application is working).

"use strict";
var react_1 = require("react");
var react_dom_1 = require("react-dom");
var RxState_js_1 = require("./state/RxState.js");
var App_jsx_1 = require("./components/App.jsx");
var reducers_1 = require("./reducers");
react_dom_1.render(react_1.createElement(RxState_js_1.RxStateProvider, {"state$": RxState_js_1.createState(reducers_1.default)}, 
    react_1.default.createElement(App_jsx_1.default, null)
), document.getElementById("root"));

For me, it looks like tsc has problems with 'default import'. If you change the beginning of RxState.js from:

import React, { PropTypes, Component } from "react";
import Rx, { Subject, Observable } from "rxjs";

export function createAction() {
  return new Subject();
}

to

import React, { PropTypes, Component } from "react";
import Rx, { Observable } from "rxjs";

export function createAction() {
  return new Rx.Subject();
}

you will encounter the same problem in this file as well (i.e. it is working with babel, but not working using only tsc).

Expected behavior:
In the described setup, it should be possible to eliminate babel and target es5 with tsc directly.

Actual behavior:
In the described setup, targeting es5 with tsc directly will not work because of problems with 'default imports'.

Question

Most helpful comment

If anyone else winds up here, the fix for me was to simply add

"module": "es2015",

to compilerOptions in tsconfig.json.

All 5 comments

I think your babel code works because it contains the es2015 preset which in turn contains the transform-es2015-modules-commonjs plugin, which is changing how default exports are transpiled.

IMO TypeScript is behaving correctly; you should import react with:

import React = require("react"); 
// or with
import * as React from "react"; 

Yes, you are right!

However, it comes to me as a surprise. Does that mean that babel is doing the _wrong_ thing with default imports? Can you give a link to the location in the spec that clarifies that tsc is doing the right thing?

The only place I know in the spec is Modules which is rather generic.

But you might want to read about babel:

BTW, the suggested changes in the import statements _also_ work with babel 6!

I seems that the button line is: Use

import * as X from Y

instead

import X from Y

as default import syntax!

If anyone else winds up here, the fix for me was to simply add

"module": "es2015",

to compilerOptions in tsconfig.json.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dlaberge picture dlaberge  路  3Comments

Zlatkovsky picture Zlatkovsky  路  3Comments

bgrieder picture bgrieder  路  3Comments

wmaurer picture wmaurer  路  3Comments

MartynasZilinskas picture MartynasZilinskas  路  3Comments