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'.
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.
Most helpful comment
If anyone else winds up here, the fix for me was to simply add
"module": "es2015",
to compilerOptions in tsconfig.json.