Typescript


Typescript is Open source programming language from Microsoft.
It is a typed superset of javascript.
Compiles down to javascript.
Relation to javascript (it is related to JS).
Optional static typing (we can add types to variable so we can get errors at compile time, type is optional for variables).
Enhanced IDE support (Typescript provide intellisense and ability to refactor the code ).
Rapid growth and use.

Environment Setup
You can download typescript from online install it using node (npm install -g typescript) or it is inbuilt with visual studio from 2015 IDE.
You can compile TS through command line “tsc file.ts”, it generate .js file.

Variable declarations:
let and const are two relatively new types of variable declarations in JavaScript.  let is similar to var(let uses block level scoping but var uses global level scope). const prevents re-assignment to a variable.

Variable Types
let isBoolean: Boolean = true;
let word: string = "is this word??";
let numberOfCount: Number = 10;
let sentense: string = `hello this is long sentense of ${word}
test one see`;
let count: number[] = [10, 2, 2, 5]; //Array

Tuple types allow you to express an array where the type of a fixed number of elements is known, but need not be the same.
// Declare a tuple type
let x: [string, number]; 
// Initialize it
x = ["hello", 10]; // OK

Enum
A helpful addition to the standard set of datatypes from JavaScript is the enum.
enum Color {Red = 1, Green, Blue}
let c: Color = Color.Green;

Any
We may need to describe the type of variables that we do not know when we are writing an application. These values may come from dynamic content, e.g. from the user or a 3rd party library. In these cases, we want to opt-out of type-checking and let the values pass through compile-time checks. To do so, we label these with the any type:
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a Boolean

Object
object is a type that represents the non-primitive type, i.e. any thing that is not number, string, boolean, symbol, null, or undefined.
With object type, APIs like Object.create can be better represented. For example:
declare function create(o: object | null): void;
create({ prop: 0 }); // OK
create(null); // OK
create(42); // Error
create("string"); // Error
create(false); // Error
create(undefined); // Error

Functions
Functions are the fundamental building block of any applications in JavaScript. They’re how you build up layers of abstraction, mimicking classes, information hiding, and modules. In TypeScript, while there are classes, namespaces, and modules, functions still play the key role in describing how to do things. TypeScript also adds some new capabilities to the standard JavaScript functions to make them easier to work with.
function add(x: number, y: number): number {
    return x + y;
}
Console.log(add(10,30));

Optional and Default Parameters
In TypeScript, every parameter is assumed to be required by the function. In short, the number of arguments given to a function has to match the number of parameters the function expects.
function buildName(firstName: string, lastName: string) {
    return firstName + " " + lastName;
}
let result1 = buildName("Bob");                  // error, too few parameters
let result2 = buildName("Bob", "Adams", "Sr.");  // error, too many parameters
let result3 = buildName("Bob", "Adams");         // ah, just right

In JavaScript, every parameter is optional, and users may leave them off as they see fit. When they do, their value is undefined. We can get this functionality in TypeScript by adding a ? to the end of parameters we want to be optional.
function buildName(firstName: string, lastName?: string) {
    if (lastName)
        return firstName + " " + lastName;
    else
        return firstName;
}

let result1 = buildName("Bob");                  // works correctly now
let result2 = buildName("Bob", "Adams", "Sr.");  // error, too many parameters
let result3 = buildName("Bob", "Adams");         // ah, just right
In TypeScript, we can also set a value that a parameter will be assigned if the user does not provide one, or if the user passes undefined in its place.
function buildName(firstName: string, lastName = "Smith") {
    return firstName + " " + lastName;
}
let result1 = buildName("Bob");                  // works correctly now, returns "Bob Smith"
let result2 = buildName("Bob", undefined);       // still works, also returns "Bob Smith"

Interface
One of TypeScript’s core principles is that type-checking focuses on the shape that values have. This is sometimes called “duck typing” or “structural subtyping”. In TypeScript, interfaces fill the role of naming these types, and are a powerful way of defining contracts within your code as well as contracts with code outside of your project.
example:
function printLabel(labelledObj: { label: string }) {
    console.log(labelledObj.label);
}
let myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);
The type-checker checks the call to printLabel. The printLabel function has a single parameter that requires that the object passed in has a property called label of type string. Notice that our object actually has more properties than this, but the compiler only checks that at least the ones required are present and match the types required. There are some cases where TypeScript isn’t as lenient, which we’ll cover in a bit.
We can write the same example again, this time using an interface to describe the requirement of having the label property that is a string:
interface LabelledValue {
    label: string;
}

function printLabel(labelledObj: LabelledValue) {
    console.log(labelledObj.label);
}
let myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);

Optional Properties
Not all properties of an interface may be required. Some exist under certain conditions or may not be there at all.
interface SquareConfig {
    color?: string;
    width?: number;
}
function createSquare(config: SquareConfig): {color: string; area: number} {
    let newSquare = {color: "white", area: 100};
    if (config.color) {
        newSquare.color = config.color;
    }
    if (config.width) {
        newSquare.area = config.width * config.width;
    }
    return newSquare;
}

let mySquare = createSquare({color: "black"});

Implementing an interface
One of the most common uses of interfaces in languages like C# and Java, that of explicitly enforcing that a class meets a particular contract, is also possible in TypeScript.
interface ClockInterface {
    currentTime: Date;
}
class Clock implements ClockInterface {
    currentTime: Date;
    constructor(h: number, m: number) { }
}

Extending Interfaces
Like classes, interfaces can extend each other. This allows you to copy the members of one interface into another, which gives you more flexibility in how you separate your interfaces into reusable components.
interface Shape {
    color: string;
}
interface Square extends Shape {
    sideLength: number;
}
let square = <Square>{};
square.color = "blue";
square.sideLength = 10;

Classes
Traditional JavaScript uses functions and prototype-based inheritance to build up reusable components, but this may feel a bit awkward to programmers more comfortable with an object-oriented approach, where classes inherit functionality and objects are built from these classes. Starting with ECMAScript 2015, also known as ECMAScript 6, JavaScript programmers will be able to build their applications using this object-oriented class-based approach. In TypeScript, we allow developers to use these techniques now, and compile them down to JavaScript that works across all major browsers and platforms, without having to wait for the next version of JavaScript.
Classes
Let’s take a look at a simple class-based example:
class Greeter {
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
    }
    greet() {
        return "Hello, " + this.greeting;
    }
}
let greeter = new Greeter("world");
Example 2: class Animal {
    name: string;
    constructor(theName: string) { this.name = theName; }
    move(distanceInMeters: number = 0) {
        console.log(`${this.name} moved ${distanceInMeters}m.`);
    }
}
class Snake extends Animal {
    constructor(name: string) { super(name); }
    move(distanceInMeters = 5) {
        console.log("Slithering...");
        super.move(distanceInMeters);
    }
}
class Horse extends Animal {
    constructor(name: string) { super(name); }
    move(distanceInMeters = 45) {
        console.log("Galloping...");
        super.move(distanceInMeters);
    }
}
let sam = new Snake("Sammy the Python");
let tom: Animal = new Horse("Tommy the Palomino");
sam.move();
tom.move(34);

Type compatibility
Type compatibility in TypeScript is based on structural subtyping. Structural typing is a way of relating types based solely on their members. This is in contrast with nominal typing. Consider the following code:
interface Named {
    name: string;
}
class Person {
    name: string;
}
let p: Named;
// OK, because of structural typing
p = new Person();

Iterators and Generators
Iterables
An object is deemed iterable if it has an implementation for the Symbol.iterator property. Some built-in types like Array, Map, Set, String, Int32Array, Uint32Array, etc. have their Symbol.iterator property already implemented. Symbol.iterator function on an object is responsible for returning the list of values to iterate on.
for..of statements
for..of loops over an iterable object, invoking the Symbol.iterator property on the object. Here is a simple for..of loop on an array:
let someArray = [1, "string", false];
for (let entry of someArray) {
    console.log(entry); // 1, "string", false
}
for..of vs. for..in statements
Both for..of and for..in statements iterate over lists; the values iterated on are different though, for..in returns a list of keys on the object being iterated, whereas for..of returns a list of values of the numeric properties of the object being iterated.
Here is an example that demonstrates this distinction:
let list = [4, 5, 6];
for (let i in list) {
   console.log(i); // "0", "1", "2",
}
for (let i of list) {
   console.log(i); // "4", "5", "6"

Namespace
A namespace is a way to logically group related code. This is inbuilt into TypeScript unlike in JavaScript where variables declarations go into a global scope and if multiple JavaScript files are used within same project there will be possibility of overwriting or misconstruing the same variables, which will lead to the “global namespace pollution problem” in JavaScript.
Defining a Namespace
A namespace definition begins with the keyword namespace followed by the namespace name as follows −
namespace SomeNameSpaceName {
   export interface ISomeInterfaceName {      } 
   export class SomeClassName {      } 
}
The classes or interfaces which should be accessed outside the namespace should be marked with keyword export.
To access the class or interface in another namespace, the syntax will be namespaceName.className
SomeNameSpaceName.SomeClassName;
If the first namespace is in separate TypeScript file, then it should be referenced using triple slash reference syntax.
/// <reference path = "SomeFileName.ts" />

Splitting Across Files
As our application grows, we’ll want to split the code across multiple files to make it easier to maintain.
Multi-file namespaces
We can split long namespace across many files. Even though the files are separate, they can each contribute to the same namespace and can be consumed as if they were all defined in one place. Because there are dependencies between files, we’ll add reference tags to tell the compiler about the relationships between the files.
Validation.ts
namespace Validation {
    export interface StringValidator {
        isAcceptable(s: string): boolean;
    }
}
LettersOnlyValidator.ts
/// <reference path="Validation.ts" />
namespace Validation {
    const lettersRegexp = /^[A-Za-z]+$/;
    export class LettersOnlyValidator implements StringValidator {
        isAcceptable(s: string) {
            return lettersRegexp.test(s);
        }
    }
}
ZipCodeValidator.ts
/// <reference path="Validation.ts" />
namespace Validation {
    const numberRegexp = /^[0-9]+$/;
    export class ZipCodeValidator implements StringValidator {
        isAcceptable(s: string) {
            return s.length === 5 && numberRegexp.test(s);
        }
    }
}
Test.ts
/// <reference path="Validation.ts" />
/// <reference path="LettersOnlyValidator.ts" />
/// <reference path="ZipCodeValidator.ts" />

// Some samples to try
let strings = ["Hello", "98052", "101"];

// Validators to use
let validators: { [s: string]: Validation.StringValidator; } = {};
validators["ZIP code"] = new Validation.ZipCodeValidator();
validators["Letters only"] = new Validation.LettersOnlyValidator();

// Show whether each string passed each validator
for (let s of strings) {
    for (let name in validators) {
        console.log(`"${ s }" - ${ validators[name].isAcceptable(s) ? "matches" : "does not match" } ${ name }`);
    }
}

Module
A module is designed with the idea to organize code written in TypeScript. Modules are broadly divided into −
·       Internal Modules
·       External Modules
Internal Module
Internal modules came in earlier version of Typescript. This was used to logically group classes, interfaces, functions into one unit and can be exported in another module. This logical grouping is named namespace in latest version of TypeScript. So internal modules are obsolete instead we can use namespace. Internal modules are still supported, but its recommended to use namespace over internal modules.
Internal Module Syntax (Old)
module TutorialPoint {
   export function add(x, y) { 
      console.log(x+y);
   }
}
Namespace Syntax (New)
namespace TutorialPoint {
   export function add(x, y) { console.log(x + y);}
}
JavaScript generated in both cases are same
var TutorialPoint;
(function (TutorialPoint) {
   function add(x, y) {
      console.log(x + y);
   }
   TutorialPoint.add = add;
})(TutorialPoint || (TutorialPoint = {}));

External Module
External modules in TypeScript exists to specify and load dependencies between multiple external js files. If there is only one js file used, then external modules are not relevant. Traditionally dependency management between JavaScript files was done using browser script tags (<script></script>). But that’s not extendable, as its very linear while loading modules. That means instead of loading files one after other there is no asynchronous option to load modules. When you are programming js for the server for example NodeJs you don’t even have script tags.

There are two scenarios for loading dependents js files from a single main JavaScript file.
Client Side - RequireJs
Server Side - NodeJs
Selecting a Module Loader
To support loading external JavaScript files, we need a module loader. This will be another js library. For browser the most common library used is RequieJS. This is an implementation of AMD (Asynchronous Module Definition) specification. Instead of loading files one after the other, AMD can load them all separately, even when they are dependent on each other.
Defining External Module
When defining external module in TypeScript targeting CommonJS or AMD, each file is considered as a module. So it’s optional to use internal module with in external module.
If you are migrating TypeScript from AMD to CommonJs module systems, then there is no additional work needed. The only thing you need to change is just the compiler flag Unlike in JavaScript there is an overhead in migrating from CommonJs to AMD or vice versa.
The syntax for declaring an external module is using keyword ‘export’ and ‘import’.
Syntax
//FileName : SomeInterface.ts
export interface SomeInterface {
   //code declarations
}
To use the declared module in another file, an import keyword is used as given below. The file name is only specified no extension used.
import someInterfaceRef = require(“./SomeInterface”);
Example
Let’s understand this using an example.
// IShape.ts
export interface IShape {
   draw();
}

// Circle.ts
import shape = require("./IShape");
export class Circle implements shape.IShape {
   public draw() {
      console.log("Cirlce is drawn (external module)");
   }
}

// Triangle.ts
import shape = require("./IShape");
export class Triangle implements shape.IShape {
   public draw() {
      console.log("Triangle is drawn (external module)");
   }
}
  
// TestShape.ts
import shape = require("./IShape");
import circle = require("./Circle");
import triangle = require("./Triangle"); 

function drawAllShapes(shapeToDraw: shape.IShape) {
   shapeToDraw.draw();
}

drawAllShapes(new circle.Circle());
drawAllShapes(new triangle.Triangle());
The command to compile the main TypeScript file for AMD systems is −
tsc --module amd TestShape.ts
On compiling, it will generate following JavaScript code for AMD.

Namespace vs module.

A namespace is a way to logically group related code.
They can span multiple files, and can be concatenated using --outFile. Namespaces can be a good way to structure your code in a Web Application, with all dependencies included as <script> tags in your HTML page.
Just like all global namespace pollution, it can be hard to identify component dependencies, especially in a large application.

Just like namespaces, modules can contain both code and declarations. The main difference is that modules declare their dependencies.
Modules import one another using a module loader. At runtime the module loader is responsible for locating and executing all dependencies of a module before executing it.

Ambient declarations are a way of telling the TypeScript compiler that the actual source code exists elsewhere. When you are consuming a bunch of third party js libraries like jquery/angularjs/nodejs you can’t rewrite it in TypeScript. Ensuring typesafety and intellisense while using these libraries will be challenging for a TypeScript programmer. Ambient declarations help to seamlessly integrate other js libraries into TypeScript.
Defining Ambients
Ambient declarations are by convention kept in a type declaration file with following extension (d.ts)
Sample.d.ts
The above file will not be transcompiled to JavaScript. It will be used for type safety and intellisense.
The syntax for declaring ambient variables or modules will be as following −
Syntax
declare module Module_Name {
}
The ambient files should be referenced in the client TypeScript file as shown −
/// <reference path = " Sample.d.ts" />
Example
Let’s understand this with help of an example. Assume you been given a third party javascript library which contains code similar to this.
FileName: CalcThirdPartyJsLib.js
var TutorialPoint; 
(function (TutorialPoint) { 
   var Calc = (function () {
      function Calc() {
      }
      Calc.prototype.doSum = function (limit) {
         var sum = 0;
        
         for (var i = 0; i <= limit; i++) {
            Calc.prototype.doSum = function (limit) {
               var sum = 0;
              
               for (var i = 0; i <= limit; i++) {
                  sum = sum + i;
                  return sum;
                  return Calc;
                  TutorialPoint.Calc = Calc;
               })(TutorialPoint || (TutorialPoint = {}));
               var test = new TutorialPoint.Calc();
            }
         }
      }
   }
}  
As a typescript programmer you will not have time to rewrite this library to typescript. But still you need to use the doSum() method with type safety. What you could do is ambient declaration file. Let us create an ambient declaration file Calc.d.ts
FileName: Calc.d.ts
declare module TutorialPoint {
   export class Calc {
      doSum(limit:number) : number;
   }
}
Ambient files will not contain the implementations, it is just type declarations. Declarations now need to be included in the typescript file as follows.
FileName : CalcTest.ts 
/// <reference path = "Calc.d.ts" />
var obj = new TutorialPoint.Calc();
obj.doSum("Hello"); // compiler error
console.log(obj.doSum(10));
The following line of code will show a compiler error. This is because in the declaration file we specified the input parameter will be number.
obj.doSum("Hello");
Comment the above line and compile the program using the following syntax −
tsc CalcTest.ts
On compiling, it will generate following JavaScript code(CalcTest.js).
//Generated by typescript 1.8.10
/// <reference path = "Calc.d.ts" />
var obj = new TutorialPoint.Calc();

// obj.doSum("Hello");
console.log(obj.doSum(10));
In order to execute the code, let us add an html page with script tags as given below. Add the compiled CalcTest.js file and the third party library file CalcThirdPartyJsLib.js.
<html>
   <body style = "font-size:30px;">
      <h1>Ambient Test</h1>
      <h2>Calc Test</h2>
   </body>
  
   <script src = "CalcThirdPartyJsLib.js"></script>
   <script src = "CalcTest.js"></script>
</html>

No comments:

Post a Comment