Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 612
dcstraw Avatar asked Oct 22 '12 16:10

dcstraw


People also ask

Does TypeScript support CommonJS?

TypeScript supports export = to model the traditional CommonJS and AMD workflow. The export = syntax specifies a single object that is exported from the module. This can be a class, interface, namespace, function, or enum.

Can I import a TypeScript into JavaScript?

Not at all, because Typescript cannot be directly executed by Javascript. You must have some tooling that takes care of converting Typescript to executable Javascript, the answer lies there.

When using TypeScript where should you import modules from?

Use import myFunction from "./myModule" to bring it in. More commonly, TypeScript modules say export myFunction in which case myFunction will be one of the properties on the exported object. Use import { myFunction } from "./myModule" to bring it in.

What is the module and how it can be imported and exported in TypeScript with example?

We can create a module by using the export keyword and can use in other modules by using the import keyword. Modules import another module by using a module loader. At runtime, the module loader is responsible for locating and executing all dependencies of a module before executing it.


2 Answers

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.

like image 172
ryan Avatar answered Sep 18 '22 01:09

ryan


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'] },
  }
});
like image 24
Eric Lee Avatar answered Sep 21 '22 01:09

Eric Lee