- updated README.md with a more efficient way to integrate Dojo and TypeScripts' class systems
4.2 KiB
Dojo Definitions Usage Notes
Overview
Anyone that has used Dojo for any length of time has probably discovered three things:
- Dojo is very powerful
- Dojo can be challenging to learn
- Dojo doesn't always play well with other
Having said that, there are ways that Dojo can be coerced out of its shell to work with other JavaScript technologies. This README is intended to describe some techniques for getting the full power of Dojo to work in an environment where almost everything can take advantage of TypeScript.
Disclaimer: Dojo is VERY big framework and, as such the type definitions are generated by a tool from dojo's API docs. The generated files were then hand-polished to eliminate any import errors and clean up some obvious errors. This is all to say that the generated type definitions are not flawless and are not guaranteed to reflect the actual implementations.
Basic Usage
A normal dojo module might look something like this:
define(['dojo/request', 'dojo/request/xhr'],
function (request, xhr) {
...
}
);
When using the TypeScript, you can write the following:
import request = require("dojo/request");
import xhr = require("dojo/request/xhr");
...
Inside of the define variable, both request and xhr will work as the functions that come from Dojo, only they are strongly typed.
Advanced Usage
Dojo and TypeScript both use different and conflicting class semantics. This causes some issues when trying to create custom class modules that are strongly typed in other modules. The following technique is presented as A solution to the problem, but not necessarily the best one. Other ideas a welcomed!
Using pure JavaScript, a class that has a base class and mixins can be defined in Dojo as follows:
define(['dojo/_base/declare', 'dijit/_WidgetBase', 'dijit/_TemplatedMixin', 'dojo/request'],
function(dojoDeclare, _WidgetBase, _TemplatedMixin, request) {
var Foo = dojoDeclare([_WidgetBase, _TemplatedMixin], {
templateString: '<div>Hello TypeScript</div',
message: '',
sayMessage: function() {
alert(this.message);
},
getServerInfo: function() {
request.get('http://dojoAndTypeScriptTogetherAtLast.html', function(data) {
console.log(data);
});
}
});
return Foo;
}
);
The goal is to be able to describe the Foo class in a way that TypeScript can recognize, but also works with Dojo. This requires some hacks that will be introduced and explained as the problems are discovered.
The first challenge that we run into is how to define the class. We will define that using standard TypeScript semantics as follows:
import dojoDeclare = require("dojo/_base/declare");
import _WidgetBase = require("dijit/_WidgetBase");
import _TemplatedMixin = require("dijit/_TemplatedMixin");
import template = require("dojo/text!./_templates/View.html");
class Foo extends dijit._WidgetBase {
message: String = "";
constructor(args?: Object, element?: HTMLElement) {
return new FooType(args, element);
}
sayMessage() {
alert(this.message);
}
getServerInfo() {
request.get('http://dojoAndTypeScriptTogetherAtLast.html', function(data) {
console.log(data);
});
}
}
var FooType = dojoDeclare("", <Function[]>[_WidgetBase, _TemplatedMixin], {
templateString: '<div>Hello TypeScript</div',
sayMessage: Foo.prototype.sayMessage,
getServerInfo: Foo.prototype.getServerInfo
});
export =Foo;
In short, we create the class using the standard TypeScript methodology. The constructor, howevever, defers to Dojo-style class declaration (i.e. FooType) that is created afterward. Conversely, the Dojo-style class pulls the implementation of its methods from the prototype of the TypeScript class. It is a little cumbersome to have to do this, but I haven't been able to find another way to satisfy both TypeScript and Dojo's class systems otherwise. If you find a better way, feel free to let me know!