How to create Ambient Declarations in TypeScript Tutorial
Posted by robert | Filed under TypeScript
In this TypeScript tutorial I will show you how to create a Ambient Declarations file for a popular JavaScript library. There is a few ways to create ambient declarations. Two that I know of are a Ambient Interface Declaration and a Ambient Class Declaration.
Ambient Interface Declaration
I just created one for GreenSock’s TweenMax, TweenLite, etc. tweening JavaScript library. Check out the full TypeScript Ambient Declarations Class for GreenSock TweenMax/TweenLite and the rest of the JavaScript library.
I am going to take a few examples from the GreenSock JavaScript Docs http://api.greensock.com/js/
One thing is if you want to get things up and running fast all you needed to do is declare a variable for what JavaScript class you wan to use. For example I wanted to use TweenLite for my HTML5 Canvas Banner ad so I setup a file called greensock.d.ts and had the code below in it.
declare var TweenLite:any;
This will work but you will get not any intelli-sense or type checking.
Then I imported that file into the top of my main TypeScript file like:
///<reference path='greensock.d.ts'/>
Once I imported the declaration file I can called the TweenLite.to() method in my TypeScript file. Which animates an object called objectToAnimate for 1 sec to the x position of 156 and a y position of 200. Since we have a GreenSock declaration file we won’t get any compiling errors.
TweenLite.to(this.objectToAnimate, 1, {x:156, y:200});
I am lucky that GreenSock is well documented which made making a the declaration file easy. Below is the public methods for the TweenLite.
delayedCall(delay:Number, callback:Function, params:Array = null, scope:* = null, useFrames:Boolean = false):TweenLite from(target:Object, duration:Number, vars:Object):TweenLite fromTo(target:Object, duration:Number, fromVars:Object, toVars:Object):TweenLite getTweensOf(target:*):Array invalidate():* killDelayedCallsTo(func:Function):void killTweensOf(target:*, vars:Object = null):void set(target:Object, vars:Object):TweenLite to(target:Object, duration:Number, vars:Object):TweenLite
Below is the converted public methods into TypeScript.
interface TweenLite { delayedCall(delay:number, callback:Function, params?:any[], scope?:any, useFrames?:bool):TweenLite; from(target:Object, duration:number, vars:Object):TweenLite; fromTo(target:Object, duration:number, fromVars:Object, toVars:Object):TweenLite; getTweensOf(target:Object):any[]; invalidate():any; killDelayedCallsTo(func:Function):void; killTweensOf(target:Object, vars?:Object):void; set(target:Object, vars:Object):TweenLite; to(target:Object, duration:number, vars:Object):TweenLite; }
Ambient Class Declaration (Value of type is not newable)
Now to work with raw JavaScript classes(not TypeScript classes) within TypeScript we need to create an Ambient Class Declaration so we can write var something = new SomethingClass();. I ran into this issue when playing with RouterJS and the TypeScript compiler said “Value of type ‘Router’ is not newable”. This is because I was trying to create a Ambient Interface Declaration for RouterJS. Below is how I solved that problem. Also notice the constructor and how we set it to have an optional parameter.
class Router { // properties trigger:bool; // methods route(route:string, callback:Function):any[]; checkRoutes(state:Object):bool; navigate(url:string, trigger?:bool, replace?:bool, name?:string):any; go(num:number):any; back(num:number):any; //constructor constructor (router?:Object); }
We can take it a step further to deal with JavaScript libraries that have namespacing. If you look below we create a module for the namespace(createjs) and then we export the class(DisplayObject). I got this example from DefinitelyTyped.
module createjs { export class DisplayObject { // properties static suppressCrossDomainErrors: bool; visible: bool; x: number; y: number; constructor (); // methods cache(x: number, y: number, width: number, height: number, scale?: number): void; clone(): DisplayObject; draw(ctx: CanvasRenderingContext2D, ignoreCache?: bool): void; // events onClick: (event: MouseEvent) => any; onDoubleClick: (event: MouseEvent) => any; onMouseOut: (event: MouseEvent) => any; onMouseOver: (event: MouseEvent) => any; onPress: (event: MouseEvent) => any; onTick: () => any; } }
When you type your arguments, use the following types:
String’s will be typed as :string
Number’s will be typed as :number
Boolean’s will be typed as :bool
Object’s will still be :Object
Array’s will be typed as :any[]
Untyped or * will be typed as :any
Function’s will be typed as :Function
Things to note when making a declaration file is always end the lines with a semi-colon ;. Any argument value that can me be null or has a default value put a ? after the argument name and if there are any other arguments after that one do the same. This tells the compiler that these arguments are optional. Example:
method(one:number, two?:any[], three?:any, four?:bool):void;
Also if you like this tutorial please provide a link back to this page or my site.
December 12, 2012 at 10:20 am
Thanks! Very helpful — I found this, a number of declaration files already done — https://github.com/borisyankov/DefinitelyTyped — perhaps helpful to you.
December 12, 2012 at 12:53 pm
Hey, thanks! I’ve contributed to DefinitelyTyped. I added the GreenSock TypeScript file.