I thought I would share our solution for robust Kendo+Typescript+Requirejs support, in the hope that Telerik starts including this out of the box in Kendo.
THE PROBLEM
Currently the Kendo typescript definitions don't include any declarations of AMD modules for use with requirejs. While it is possible to work around this in a number of ways to at least get the require("<kendo file>") statements to emit into the javascript code, the fundamental issue is that the Typescript compiler is not aware of which kendo classes belong in which AMD module. This means that you can write typescript code that compiles fine, but does not actually work at run-time. For example:
This will compile fine because as far as the compiler is concerned the entire kendo library is always loaded and global. However when you run the resultant javascript from the above code, it will fail because kendo.bind is not within the require chain of kendo.data.js.
This becomes very annoying because you are never 100% sure you are requiring the correct kendo modules actually needed for the code you write.
OUR SOLUTION
The solution we are using is to define our own kendo AMD module definitions, and have them explicitly re-export the named types from the kendo global scope out of the AMD module. Each AMD module only re-exports the kendo types that are actually contained within that modules kendo javascript file. For example in our new kendo.web.amd.d.ts file (which contains all the AMD module defs in one file) we have:
The compiler is now aware of kendo.data.js as a proper AMD module, and knows exactly which types are available out of it. The leading "kendo/" is required so that we can configure requirejs to map to the actual kendo library path. As long as we avoid referring to the global kendo module in our typescript code, we now guarantee that if code compiles, it will also be pulling in the correct modules at runtime. The original example now looks like this:
Note that we no longer reference the global "kendo" module, we only use types within the modules we have explicitly imported. Intellisense is smart enough to drop down all types available in the module, for example here typing "kendoData." will drop down everything available out of that AMD module.
A BETTER SOLUTION
The only problem with the above solution is that the global module is still available to the typescript compiler, so if you accidentally reference a type straight out of the global "kendo", you are back to the original problem where it will compile fine, but then fail at runtime. A better solution would be for Telerik to provide two versions of each definition file, ie
kendo.web.ts
kendo.web.amd.ts
The .amd version, rather than just declaring all types in the global kendo namespace, would declare each type within the actual named module that it resided in (with the leading "kendo/" to allow path remapping!!). Within our projects we could then choose to include only the kendo.web.amd file, which would enforce that no kendo types are available unless you import the associated module.
THE PROBLEM
Currently the Kendo typescript definitions don't include any declarations of AMD modules for use with requirejs. While it is possible to work around this in a number of ways to at least get the require("<kendo file>") statements to emit into the javascript code, the fundamental issue is that the Typescript compiler is not aware of which kendo classes belong in which AMD module. This means that you can write typescript code that compiles fine, but does not actually work at run-time. For example:
import kendoData = require(
"kendo\kendo.data"
);
// I want to do something with data, emit require statement
var
data =
new
kendo.data.ObservableObject()
kendo.bind(
"#target"
, data);
This will compile fine because as far as the compiler is concerned the entire kendo library is always loaded and global. However when you run the resultant javascript from the above code, it will fail because kendo.bind is not within the require chain of kendo.data.js.
This becomes very annoying because you are never 100% sure you are requiring the correct kendo modules actually needed for the code you write.
OUR SOLUTION
The solution we are using is to define our own kendo AMD module definitions, and have them explicitly re-export the named types from the kendo global scope out of the AMD module. Each AMD module only re-exports the kendo types that are actually contained within that modules kendo javascript file. For example in our new kendo.web.amd.d.ts file (which contains all the AMD module defs in one file) we have:
declare module
"kendo/kendo.data"
{
module data {
export import Datasource = kendo.data.DataSource;
export import ObservableObject = kendo.data.ObservableObject;
}
}
The compiler is now aware of kendo.data.js as a proper AMD module, and knows exactly which types are available out of it. The leading "kendo/" is required so that we can configure requirejs to map to the actual kendo library path. As long as we avoid referring to the global kendo module in our typescript code, we now guarantee that if code compiles, it will also be pulling in the correct modules at runtime. The original example now looks like this:
import kendoData = require(
"kendo\kendo.data"
);
import kendoBind = require(
"kendo\kendo.binder"
);
var
data =
new
kendoData.data.ObservableObject();
kendoBind.bind(
"#target"
, data);
Note that we no longer reference the global "kendo" module, we only use types within the modules we have explicitly imported. Intellisense is smart enough to drop down all types available in the module, for example here typing "kendoData." will drop down everything available out of that AMD module.
A BETTER SOLUTION
The only problem with the above solution is that the global module is still available to the typescript compiler, so if you accidentally reference a type straight out of the global "kendo", you are back to the original problem where it will compile fine, but then fail at runtime. A better solution would be for Telerik to provide two versions of each definition file, ie
kendo.web.ts
kendo.web.amd.ts
The .amd version, rather than just declaring all types in the global kendo namespace, would declare each type within the actual named module that it resided in (with the leading "kendo/" to allow path remapping!!). Within our projects we could then choose to include only the kendo.web.amd file, which would enforce that no kendo types are available unless you import the associated module.