Tuesday, November 8, 2016

TypeScript : Writing first typedefinition file for our JavaScript library

TypeScript doesn't have its own runtime. But it makes the JavaScript coding much easier and maintainable. TypeScript and JavaScript goes hand in hand as every valid JavaScript is valid TypeScript. But what if we already have a JavaScript library and we don't have budget to convert that to TypeScript. Can TypeScript call JavaScript functions inside the library?

A JavaScript Library

Wiki says "JavaScript library is a library of pre-written JavaScript which allows for easier development of JavaScript-based applications..". Mainly JavaScript libraries expose their functionalities via objects or functions. Below is a JavaScript library to do some math functions.

//Code math opeations
var MathLib = {
    Add: function (n1, n2) { return n1 + n2; },
    Subtract: function (n1, n2) { return n1 - n2; }
}

This can be easily invoked from anywhere in JavaScript as its a global variable.
function btnclick() {
    alert(MathLib.Add(2,3));
}

Entering the TypeScript world

Now lets see how the above library can be used from TypeScript. If we simply copy paste the JavaScript function to call the library, it won't compile. That is because TypeScript don't know what is the type of MathLib object and don't know whether there is a function called Add() is there in that object.

So what to do? If we want to call any JavaScript library we need to make sure its available in TypeScript. That can be done by writing type definitions for JavaScript library.

declare var MathLib: IMathLib;
interface IMathLib{
    Add(n1: number, n2: number);
    Subtract(n1: number, n2: number);
}

Include the above declarations into TypeScript file then we can see it is compiling and producing same JavaScript code.

What magic happened here? We told TypeScript compiler that there is an variable called MathLib and its type is IMathLib. That type has 2 methods and the signature of those methods. We can tell that the arguments are 2 numbers. Now TypeScript passes the compilation assuming that during runtime there would be an valid object in the variable MathLib with 2 functions with proper names.

The interface name can be anything but the function names should be exactly same. the parameter type can be any valid type in TypeScript including the 'any' type.

Virtual TypeSystem of TypeScript

The type system in TypeScript exists only during compilation. During runtime nobody is enforcing types. This is because the runtime is JavaScript and that is not a hard typed system.

What is <filename>.d.ts

d.ts extension is a convention in TypeScript used to group all the TypeDefinitions. So that our application code will never be confused with TypeDefinition files.

Just move the declare var... line to a file named defs.d.ts and include to the project. It will compile. If there are any compilation error make sure your .ts file which consumes the library has a referene to the type definition. Sample code below

/// <reference path="defs.d.ts" />
function btnclick() {
    alert(MathLib.Add(2, 3));
}

Writing TypeDefinitions for third party JavaScript library

The above clearly shows in the TypeScript world the consumer of the library can simply create the type definitions for any JavaScript library. When we want to write type definitions for large libraries better make sure we are creating proper modules so that there is a clear separation. Also use exports properly.  

The type definitions for all most all famous libraries are already available in internet. One of the repository for type definitions is DefinitelyTyped

References

http://peter.grman.at/how-to-write-typescript-definition-files/
http://www.codeproject.com/Articles/528295/ModularizationplusinplusTypeScript

No comments: