Asynchronously loading TypeScript declarations without exporting

I have several jQuery plugins that I would like to load using the AMD template in TypeScript. For example, I might have this structure:

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

The plugin simply extends jQuery. It does not provide any new functions or top-level variables. An example would be:

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

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

 interface JQuery { myExample(); } 

So now in app.ts I can name something like $('#my-element').myExample() . Note that this assumes that I already have jquery.d.ts ads from a downloaded by Microsoft.

My question is how to load this library asynchronously and use TypeScripts static typing? I could use it like this:

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

but this requires me to add the <script> to my HTML, and the library does not load 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 is no export in the .d.ts file, I cannot write import myplugin = module('lib/jquery.myplugin') .

The closest I got is to make jquery.myplugin.d.ts , which links to another ts file with an interface declaration and includes at least one export. However, there is nothing to export in this library, and to get the desired result, I need to not only add the export, but also call it.

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

+6
javascript typescript js-amd
source share
3 answers

Typescript will not import modules if they do not export anything, and if you do not directly use what they exported, but these things are not true for things like JQuery plugins that simply add new methods to $. The solution is to use the amd dependency flag as described here .

Add a line similar to this at the top of the file:

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

This will force Typescript to list it in the define call in compiled Javascript. You also need to configure the path and layout for your plugin in your require.config, for example:

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

Kind of hacking, but here is the only way that I now know about.

myplugin.d.ts: extends the JQueryStatic interface to include the intellisense function for myplugin

 /// <reference path="../dep/jquery/jquery.d.ts" /> interface JQueryStatic { myFunc(): string; } 

myplugin.ts: a dummy file whose sole purpose is to 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 using 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 out intellisense for jQuery and your plugin definitions. It was necessary to create both myplugin.d.ts and myplugin.ts, because I do not know how (if possible) to export something, while expanding the existing interface in the same file without errors.

+4
source share

At the bottom of the file, which is defined by the interface inside, you can put:

 export var JQuery: JQueryStatic; 

What will make intellisense for jQuery appear on any file loaded with the import module .

If your file is loaded asynchronously and you set jQuery to another variable (i.e. myJQuery ), you can declare that the file is already loaded specific, for example, if you have a file in ///<reference path=...> , you can use:

 declare var myJQuery: JQuery; 

To create myJQuery jQuery type.

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

 interface JQueryStatic { myFunc(): string; } 

If you do not mind editing the JQuery.d.ts files, you can add your function to the interfaces specified there.

Back to your example, you should do something like:

 declare var __jquery : JQueryStatic; 

At the top of your callback definition; and if you extend the interface for JQueryStatic and enable it with ///<reference path=...> , the markup should work as desired.

+1
source share

All Articles