Sam Sippe Sam Sippe - 3 months ago 22
TypeScript Question

Module loading from Typescript with script.js

I'd like to be able to load external dependencies with typescript from a cdn like so:

declare var $script: any;


$script(["//cdnjs.cloudflare.com/ajax/libs/react/15.2.1/react.min.js",
"//cdnjs.cloudflare.com/ajax/libs/react/15.2.1/react-dom.min.js"
], () => {
import * as React from "react";
import * as ReactDOM from "react-dom";

ReactDOM.render(
<Hello compiler="TypeScript" framework="React" />,
document.getElementById("example")
);
});


The reason for doing this is you only need to have script tags on page for scriptjs and the main.js and all other external dependencies are loaded on demand by the file that requires them.

However, I get the error

error TS1232: An import declaration can only be used in a namespace or module.


...and if we move the import statements to the top of the file, they fail because the dependencies are not yet loaded.

Is there a way we can use scriptjs to load dependencies on demand with typescript?

Answer

The import statements that you're using should be used when loading script using a module loader (amd, system, etc), but since you're not doing that then you need to use the reference tags to tell the compiler where to find the definitions to react:

/// <reference path="react.d.ts" />
/// <reference path="react-dom.d.ts" />

$script(["//cdnjs.cloudflare.com/ajax/libs/react/15.2.1/react.min.js",
    "//cdnjs.cloudflare.com/ajax/libs/react/15.2.1/react-dom.min.js"
], () => {
    ReactDOM.render(
        <Hello compiler="TypeScript" framework="React" />,
        document.getElementById("example")
    );
});

The problem is that the available definitions don't export the module as React which is how it should be used in runtime.

The example in the definitions tests show this:

import React = require("react");
import ReactDOM = require("react-dom");

Which helps for compilation (no errors) but it produces this:

var React = require("react");
var ReactDOM = require("react-dom");

Which won't help you as you don't have require at runtime.

I haven't managed to get this working, and I write this answer only to pass what I tried and to give you an alternative: use a module system.
For example using SystemJS:

The config (in the html for example):

SystemJS.config({
    map: {
        react: "//npmcdn.com/react@15.3.1/dist/react.js",
        "react-dom": "//npmcdn.com/react-dom@15.3.1/dist/react-dom.js"
    }
});

SystemJS.import("YOUR_MAIN_FILE.js")
        .then(null, console.error.bind(console));

And then in the .tsx file:

import React = require("react");
import ReactDOM = require("react-dom");

ReactDOM.render(
    <Hello compiler="TypeScript" framework="React" />,
    document.getElementById("example")
);

The module system will take care of loading things for you in the right order, and the importing is pretty straight forward.
You don't have to use SystemJS, there are other module loaders which are supported by the ts compiler.

Comments