Question

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

Était-ce utile?

La 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'] },
  }
});

Autres conseils

Kind of a hack but here's the only way I currently know of.

myplugin.d.ts: extends the JQueryStatic interface to include intellisense for myplugin's functionality

/// <reference path="../dep/jquery/jquery.d.ts" />

interface JQueryStatic {
    myFunc(): string;
}

myplugin.ts: a dummy file whose only purpose is to have typescript generate an amd module definition.

var test: number = 1;

consumer.ts:

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

import myplugin = module('myplugin');

// without this typescript knows you aren't actually using the module
// and won't create the define block including your plugin
var workaround = myplugin.test;

$.myFunc();

consumer.js: generated with tsc -c --module amd consumer.ts

define(["require", "exports", 'myplugin'], function(require, exports, __myplugin__) {
    /// <reference path="myplugin.d.ts" />
    var myplugin = __myplugin__;

    // without this typescript knows you aren't actually using the module
    // and won't create the define block including your plugin
    var workaround = myplugin.test;
    $.myFunc();
})

Note that myplugin.d.ts will pull intellisense in for both jQuery and your plugin definitions. It was necessary to create both a myplugin.d.ts and myplugin.ts because I don't know how (if possible) to export something while simultaneously extending an existing interface in the same file without errors.

At the bottom of the file that the interface is defined within you can put:

export var JQuery: JQueryStatic;

Which will make the intellisense for JQuery show up on any file loaded using import module.

If your file is being loaded asynchronously and you're setting JQuery to another variable (i.e. myJQuery) you can declare that the file has already been loaded by a certain point, for example, if you have the file in your ///<reference path=...> you should be able to use:

declare var myJQuery: JQuery;

To make your myJQuery of type JQuery.

Another hack is to insert the interface directly into the area where the code is being loaded asynchronously:

interface JQueryStatic {
    myFunc(): string;
}

If you don't mind editing your JQuery.d.ts files, you can add your function to the interfaces defined in there.

Related back to your example, you should be able to do something like:

declare var __jquery : JQueryStatic;

At the top of your define callback; and provided you've extended the interface for JQueryStatic and included it using ///<reference path=...> the markup should work as desired.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top