Using jQuery plugin in TypeScript

The issue with jQuery plugins (and other plugin based libraries) is that not only do you need a library.d.ts file for the base library, but you also need a plugin.d.ts file for each plugin. And somehow thes plugin.d.ts files need to extend the library interfaces defined in the library.d.ts files. Fortunately, TypeScript has a nifty little feature that lets you do just that.

With classes there currently can only be a single cononical definition of a class within a project. So if you define a class Foo the members you put on Foo are all you get. Any additional definitions of Foo will result in an error. With interfaces, however, the members are additive so if you define interface Bar with a set of members you can define 'interface Bar' a second time to add additional members to the interface. That's the key to supporting jQuery plugins in a strongly typed way.

So to add support for a given jQuery plugin you're going to need to create a plugin.d.ts file for the plugin you want to use. We use jQuery Templates in our project so here's the jquery.tmpl.d.ts file we created to add support for that plugin:

interface JQuery
{
    tmpl(data?:any,options?:any): JQuery;
    tmplItem(): JQueryTmplItem;
    template(name?:string): ()=>any;
}

interface JQueryStatic
{
    tmpl(template:string,data?:any,options?:any): JQuery;
    tmpl(template:(data:any)=>string,data?:any,options?:any): JQuery;
    tmplItem(element:JQuery): JQueryTmplItem;
    tmplItem(element:HTMLElement): JQueryTmplItem;
    template(name:string,template:any): (data:any)=>string[];
    template(template:any): JQueryTemplateDelegate;
}

interface JQueryTemplateDelegate {
    (jQuery: JQueryStatic, data: any):string[];
}

interface JQueryTmplItem
{
    data:any;
    nodes:HTMLElement[];
    key:number;
    parent:JQueryTmplItem;
}

Breaking this down the first thing we did is to define the methods that get added to the JQuery interface. These let you get intellisense and type checking when you type $('#foo').tmpl(); Next we added methods to the JQueryStatic interface which show up when you type $.tmpl(); And finally the jQuery Templates plugin defines some of its own data structures so we needed to define interfaces for those structures.

Now that we have the additional interfaces definied we just need to reference them from the consuming .ts files. To do that we just add the references below to the top of our .ts file and that's it. For that file, TypeScript will see both the base jQuery methods and the plugin methods. If you use multiple plugins just make sure you refernce all of your individual plugin.d.ts files and you should be good.

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

Using a .d.ts declaration file is probably better, but as an alternative you can also use TypeScript's global augmentation and declaration merging to add methods to JQuery's interface. You can place something like the following in any of your TypeScript files:

declare global {
    interface JQuery {
        nameOfPluginMethod(arg: any): JQuery;
    }
}

Tags:

Typescript