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
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