Search code examples
javascripttypescriptjs-amd

Asynchronous load of TypeScript declarations with no exports


I have a number of jQuery plugins that I would like to load using the AMD pattern in TypeScript. For example, I might have this structure:

/lib/jquery.myplugin.js
/app.ts

The plugin simply extends jQuery. It provides no new top-level functions or variables. An example might be:

// jquery.myplugin.js
jQuery.fn.myExample = function() { ... }

The corresponding jquery.myplugin.d.ts file looks like:

interface JQuery {
    myExample();
}

So that now in app.ts I can call something like $('#my-element').myExample(). Note that this assumes I already have the jquery.d.ts declarations from Microsoft loaded.

My question is how do I load this library asynchronously and take advantage of TypeScripts static typing? I could use it like this:

/// <reference path="lib/jquery.myplugin.d.ts"/>

but that requires me to add a <script> tag to my HTML, and the library is not loaded asynchronously. I want TypeScript to generate this code:

define(["require", "exports", "lib/jquery.myplugin"], function (require, exports, __jquery.myplugin__) {
    ...
    // Use my plugin
    $('#my-element').myExample();
}

However since there are no exports in the .d.ts file I can't write import myplugin = module('lib/jquery.myplugin').

The closest I've gotten is to make a jquery.myplugin.d.ts that references another ts file with the interface declaration and includes at least one export. However there is nothing to export in this library, and in order to get the desired output I have to not only add an export but I have to call it.

Update: I have opened a work item for this on typescript.codeplex.com


Solution

  • Typescript won't import modules unless they export something and unless you directly use what they exported, but those things aren't true for things like JQuery plugins that simply add new methods to $. The solution is to use the amd-dependency flag as documented here.

    Add a line like this at the top of your file:

    ///<amd-dependency path="jgrowl" />
    

    This will force Typescript to list it in the define invocation in the compiled Javascript. You'll also need to set up a path and shim for your plugin in your require.config, like this:

    require.config({
      paths: {
        jquery: "external/jquery-2.1.1",
        jgrowl: "external/jquery.jgrowl-1.4.0.min",
      },
      shim: {
        'jgrowl': { deps: ['jquery'] },
      }
    });