Introduction to TypeScript by Winston Levi
-
Upload
winston-levi -
Category
Software
-
view
69 -
download
0
Transcript of Introduction to TypeScript by Winston Levi
Introduction to TypeScriptby Winston Levi
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
TypeScript is converted into JavaScript at compile time. JavaScript is an implementation of the ECMAScript standard. There are three versions of ECMAScript that you will come across when dealing with TypeScript.
It is the version supported in most browsers. When TypeScript compiles into JavaScript, it uses the ECMAScript 3 standards by default.
The following browsers support all the important features of ECMAScript 5 :
• Internet Explorer 9 and above. • Firefox 4 and above. • Opera 12 and above. • Safari 5.1 and above. • Chrome 7 and above.
Older versions of these browsers have only partial support for this standard.
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
ECMAScript 6 - Commonly referred to as "ES6", also known as ECMAScript Harmony. New to this Version:• Modules and classes part of the JavaScript language. TypeScript gives you immediate access to these new features, in practically all browsers.
For browser's compatibility to the ECMAScript 6 follow this link:https://kangax.github.io/compat-table/es6/
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Keep in mind to check checkbox
indicating 'Compile on save' which compiles your TypeScript file into JavaScript file on each file save.
Check checkbox indicating
'Allow implicit "any" types' to allow you to have undeclared variables in your code.
Uncheck checkbox indicating
'Allow implicit "any" types' so that compiler will catch any instance where you did not declare the variable type in your TypeScript code.
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Figure #1 TypeScript Life Cycle
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
TypeScript is referred as optionally statically typed, which means you can ask the compiler to ignore the type of a variable if you want to take advantage of dynamic typing in a particular circumstance. This mix of static and dynamic typing is already present in .NET; for example, C# is statically typed but allows dynamic types to be declared with the dynamickeyword.
As well as compile-type checking, the language constructs allow static analysis that makes it possible for development tools to highlight errors in your code at design time without the need for compilation.
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Code sample #1 - Logging Function
function log(message) {
if (typeof window.console !== 'undefined') {
window.console.log(message);
}
}
var testLog = 'Hello world';
log(testLog);
Which compiles to the following JavaScript code
Table 1: Types in Code sample #1
Name Tooltiplog (message: any) => void
message any
window.console Console
testLog string
There are several benefits to this type knowledge when it comes to writing your code. Firstly, if you try to assign a value to testLog that isn’t a string type, you will get a design-time warning and a compilation error.
Figure #2 Precise autocompletion
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Code sample #2 - Logging Function
function log(message: string) {
if (typeof window.console !== 'undefined') {
window.console.log(message);
}
}
var testLog = 'Hello world';
log(testLog);
Which compiles to the same JavaScript code as previous example
Table 2: Types in Code sample #2
Name Tooltiplog (message: sting) => void
message sting
window.console Console
testLog string
Code sample #3 - Function Call Type Checking
// allowed
log('Hello world');
// not allowed
log(1);
log(true);
log({'key': 'value'});
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Code sample #4 - Entirely Explicit Types
function log(message: string): void {
if (typeof window.console !== 'undefined') {
window.console.log(message);
}
}
var testLog: string = 'Hello world';
log(testLog);
For both examples - the produced JavaScript code remains the same as been shown before.
Code sample #5 - Pragmatic Explicit Types
function log(message: string): void {
if (typeof window.console !== 'undefined') {
window.console.log(message);
}
}
var testLog = 'Hello world';
log(testLog);
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
TypeScript has five built-in primitive types as well as the dynamic any type, and the void return type.
TypeScript Primitive Types:• number• boolean• string• null• undefined• enum
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Code sample #6 - Use of Null and Undefined The allowed declarations compiles into following JavaScript code, the not allowed part does not compiles:// allowed
var a: string = null;
var b: number = undefined;
// not allowed
var c: null;
var d: undefined;
// has a value of undefined
var e: string;
In fact, as long as the wrong code exists in TypeScript
file, it will not compile into JS file.
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
interface ILogger { }
class Logger { }
var loggerA: ILogger;
var loggerB: Logger;
// has a value of undefined
var e: string;
module MyModule {
}
var example: MyModule = MyModule;
Code sample #7 – Custom Types Using Interfaces and Classes Code sample #8 – Using a Module as a Type
This declarative code does not compiles into JS code. It is more for
your own feature code and variable consistency, prevention of
wrong type value assignment and variable tooltip.
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Another advanced type declaration allows you to specify that
the type is a function. You do this by surrounding the definition
in curly braces; for example, a function accepting a string
parameter and not returning any value would have the following
type declaration:
var exampleA: string[] = [];
Unlike other languages you may be using, the variable is initialized
using either the array literal of empty square brackets [] or the new
Array(10) constructor if you wish to specify the array length. The
type is not used on the right-hand side of the statement.
var exampleA: { (name: string): void; } = function (name: string) { };
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Here are some examples of
advanced type declarations in action:
class Logger { }
// exampleA's type is an array of Logger object.var exampleA: Logger[] = [];exampleA.push(new Logger());exampleA.push(new Logger());
// exampleB's type is a function. It accepts an argument of type string and returns a number.var exampleB: { (input: string): number; };
exampleB = function (input: string) {return 1;
};
// exampleC's type is an array of functions. Each function accepts a string and returns a number.var exampleC: { (input: string): number; } [] = [];
var exampleCFunction(input: string): number; {return 10;
}exampleC[0] = exampleCFunction;exampleC[1] = exampleCFunction;
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
A helpful addition to the standard set of datatypes from
JavaScript is the 'enum'. Like languages like C#, an
enum is a way of giving more friendly names to sets of
numeric values.
enum Color {Red, Green, Blue};
var c: Color = Color.Green;
Changing the memmbers numbering order
enum Color {Red = 1, Green, Blue};
var c: Color = Color.Green;
Or, even manually set all the values in the enum:
enum Color {Red = 1, Green = 2, Blue = 4};
var c: Color = Color.Green;
A handy feature of enums is that you can also go from a
numeric value to the name of that value in the enum.
enum Color {Red = 1, Green, Blue};
var colorName: string = Color[2];
alert(colorName);
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Hello World of Generics
function identity(arg: number): number {
return arg;
}
function identity(arg: any): any {return arg;
}
function identity<T>(arg: T): T {return arg;
}
Once we've written the generic identity function, we can
call it in one of two ways. The first way is to pass all of the
arguments, including the type argument, to the function:
var output = identity<string>("myString");
// type of output will be 'string'
The second way is also perhaps the most common. Here we
use 'type argument inference', that is, we want the compiler
to set the value of T for us automatically based on the type
of the argument we pass in:
var output = identity("myString");
// type of output will be 'string'
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
What if we also want to log the length of the argument 'arg'
to the console with each call. We might be tempted to write
this:When you begin to use generics, you'll notice that when you
create generic functions like 'identity', the compiler will
enforce that you use any generically typed parameters in the
body of the function correctly. That is, that you actually treat
these parameters as if they could be any and all types.
Let's take our 'identity' function from earlier:
Working with Generic Type Variables
function identity<T>(arg: T): T {
return arg;
}
function loggingIdentity<T>(arg: T): T {
console.log(arg.length);
// Error: T doesn't have .length
return arg;
}
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
We can alternatively write the sample example this way:Let's say that we've actually intended this function to work on
arrays of T rather that T directly. Since we're working with arrays,
the .length member should be available. We can describe this just
like we would create arrays of other types:
function loggingIdentity<T>(arg: Array<T>): Array<T> {console.log(arg.length);// Array has a .length, so no more errorreturn arg;
}function loggingIdentity<T>(arg: T[]): T[] {
console.log(arg.length);
// Array has a .length, so no more error
return arg;
}
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
We could also have used a different name for the generic type
parameter in the type, so long as the number of type
variables, and how the type variables are used line up.
The type of generic functions is just like those of non-generic
functions, with the type parameters listed first, similarly to
function declarations:
Generic Types
function identity<T>(arg: T): T {return arg;
}
var myIdentity: <T>(arg: T)=>T = identity;
function identity<T>(arg: T): T {return arg;
}
var myIdentity: <U>(arg: U)=>U = identity;
We can also write the generic type as a call signature of an
object literal type:
function identity<T>(arg: T): T {return arg;
}
var myIdentity: {<T>(arg: T): T} = identity;
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Which leads us to writing our first generic interface. Let's take the object literal from the previous example and move it to an interface:
Generic Types
interface GenericIdentityFn {<T>(arg: T): T;
}
function identity<T>(arg: T): T {return arg;
}
var myIdentity: GenericIdentityFn = identity;
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
In a similar example, we may want to move the generic
parameter to be a parameter of the whole interface. This lets us
see what type(s) were generic over (e.g. Dictionary<string>
rather than just Dictionary). This makes the type parameter
visible to all the other members of the interface.
Generic Types
interface GenericIdentityFn<T> {(arg: T): T;
}
function identity<T>(arg: T): T {return arg;
}
var myIdentity: GenericIdentityFn<number> = identity;
In addition to generic interfaces, we can also create generic
classes. Note that it is not possible to create generic enums
and modules.
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
A generic class has a similar shape to a generic interface.
Generic classes have a generic type parameter list in angle
brackets (<>) following the name of the class.
Generic Classes
This is a pretty literal use of the 'GenericNumber' class, but
you may have noticed that nothing is restricting it, to only use
the 'number' type. We could have instead used 'string' or
even more complex objects.class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
var myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };
var stringNumeric = new GenericNumber<string>();
stringNumeric.zeroValue = "";
stringNumeric.add = function(x, y) { return x + y; };
alert(stringNumeric.add(stringNumeric.zeroValue,
"test"));
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Generic Constraints
Instead of working with any and all types, we'd like
to constrain this function to work with any and all
types that also have the '.length' property. As long
as the type has this member, we'll allow it, but it's
required to have at least this member. To do so, we
must list our requirement as a constraint on what T can
be.
function loggingIdentity<T>(arg: T): T {
console.log(arg.length);
// Error: T doesn't have .length
return arg;
}
To do so, we will create an interface that describes our constraint.
Here, we will create an interface that has a single '.length' property
and then we will use this interface, and the 'extends' keyword to
denote our constraint:
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
// Now we know it has a .length property, so no more error
return arg;
}
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Generic Constraints
Because the generic function is now constrained, it will no longer work over any and all types:
loggingIdentity(3); // Error, number doesn't have a .length property
Instead, we need to pass in values whose type has all the required properties:
loggingIdentity({length: 10: value: 3});
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Using Type Parameters in Generic Constraints
In some cases, it may be useful to declare a type parameter that is constrained by another type parameter. For example,
function find<T, U extends Findable<T>>(n: T, s: U) { // errors because type parameter used in constraint
// ...
}
find(giraffe, myAnimals);
This code is not strictly identical, as the return type of the first function could have returned 'U', which the
second function pattern does not provide a means to do.
You can achieve the pattern above by replacing the type parameter with its constraint. Rewriting the example above,
function find<T>(n: T, s: Findable<T>) {
// ...
}
find(giraffe, myAnimals);
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
When creating factories in TypeScript using generics, it is
necessary to refer to class types by their constructor functions.
For example,
Using Class Types in Generics
function create<T>(c: {new(): T; }): T {
return new c();
}
A more advanced example uses the prototype property to infer
and constrain relationships between the constructor function
and the instance side of class types.
class BeeKeeper {hasMask: boolean;
}
class ZooKeeper {nametag: string;
}
class Animal {numLegs: number;
}
class Bee extends Animal {keeper: BeeKeeper;
}
class Lion extends Animal {keeper: ZooKeeper;
}
function findKeeper<A extends Animal, K> (a: {new(): A; prototype: {keeper: K}}): K {
return a.prototype.keeper;}
findKeeper(Lion).nametag; // typechecks!
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
In the following code, find out how you can model
mixins in TypeScript. After the code, we will break it
down, to understand how it works.
Mixin Sample
Along with traditional OO hierarchies, another popular
way of building up classes from reusable components is to
build them by combining simpler partial classes. You may
be familiar with the idea of mixins or traits for
languages like Scala, and the pattern has reached some
popularity in the JavaScript community.
// Disposable Mixinclass Disposable {
isDisposed: boolean;dispose() {
this.isDisposed = true;}
}
// Activatable Mixinclass Activatable {
isActive: boolean;activate() {
this.isActive = true;}deactivate() {
this.isActive = false;}
}
Sample Part #1
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
class SmartObject implements Disposable, Activatable {constructor() {
setInterval(() => console.log(this.isActive + " :" +this.isDisposed), 500);
}
interact() {this.activate();
}
// DisposableisDisposed: boolean = false;dispose: () => void;// ActivatableisActive: boolean = false;activate: () => void;deactivate: () => void;
}
applyMixins(SmartObject, [Disposable, Activatable])
var smartObj = new SmartObject();// implement activate method from Activatable class // using interact methodsetTimeout(() => smartObj.interact(), 1000);
Sample Part #2 Sample Part #3
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Sample Part #4
/////////////////////////////////////////////////////////
// Register this code somewhere in your runtime library
/////////////////////////////////////////////////////////
function applyMixins(derivedCtor: any, baseCtors: any[]) {
baseCtors.forEach(baseCtor => {
Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
derivedCtor.prototype[name] = baseCtor.prototype[name];
})
});
}
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
The code sample starts with the two classes that will act
as our mixins. You can see that each one focuses on a
particular activity or capability. We will later mix these
together to form a new class from both capabilities.
Understanding the Sample // Disposable Mixinclass Disposable {
isDisposed: boolean;dispose() {
this.isDisposed = true;}
}
// Activatable Mixinclass Activatable {
isActive: boolean;activate() {
this.isActive = true;}deactivate() {
this.isActive = false;}
}
Sample Part #1
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
class SmartObject implements Disposable, Activatable {constructor() {
setInterval(() => console.log(this.isActive + " :" +this.isDisposed), 500);
}
interact() {this.activate();
}
// DisposableisDisposed: boolean = false;dispose: () => void;// ActivatableisActive: boolean = false;activate: () => void;deactivate: () => void;
}
applyMixins(SmartObject, [Disposable, Activatable])
var smartObj = new SmartObject();// implement activate method from Activatable class // using interact methodsetTimeout(() => smartObj.interact(), 1000);
Sample Part #2 Sample Part #3
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Sample Part #4
/////////////////////////////////////////////////////////
// Register this code somewhere in your runtime library
/////////////////////////////////////////////////////////
function applyMixins(derivedCtor: any, baseCtors: any[]) {
baseCtors.forEach(baseCtor => {
Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
derivedCtor.prototype[name] = baseCtor.prototype[name];
})
});
}
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
The code sample starts with the two classes that will act
as our mixins. You can see that each one focuses on a
particular activity or capability. We will later mix these
together to form a new class from both capabilities.
Understanding the Sample // Disposable Mixinclass Disposable {
isDisposed: boolean;dispose() {
this.isDisposed = true;}
}
// Activatable Mixinclass Activatable {
isActive: boolean;activate() {
this.isActive = true;}deactivate() {
this.isActive = false;}
}
Sample Part #1
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Next, we are creating the class that will handle the combination of the two mixins. Let's look at this in more detail to see how it does
this:
Understanding the Sample continued
class SmartObject implements Disposable, Activatable {
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Understanding the Sample continued Finally, we mix our mixins into the class, creating the full
implementation by calling to the following function.
applyMixins(SmartObject, [Disposable, Activatable])
// Disposable
isDisposed: boolean = false;
dispose: () => void;
// Activatable
isActive: boolean = false;
activate: () => void;
deactivate: () => void;
Properties and their types declaration for the members
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Understanding the Sample continued
This function is needed somewhere in program from where it can be accessed by all the mixins – it has to be included only once.
This function may be wrapped within a module or a class, if you want it.
function applyMixins(derivedCtor: any, baseCtors: any[]) {
baseCtors.forEach(baseCtor => {
Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
derivedCtor.prototype[name] = baseCtor.prototype[name];
})
});
}
The Important bits of this example are:
• You use the implements keyword, not the extends keyword.• You need to have a matching signature to keep the compiler quiet (but it does not need real implementation – it will get that from the mixin).• You need to call applyMixins with the correct arguments.
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
For variables and parameters that are initialized with a value, TypeScript will infer the type from the initial value. For example,
TypeScript infers the correct types for all of the following examples by inspecting the initial value even if the initial value comes from
another variable:
Code sample #8 – Type Inference
class ExampleClass {}
function myFunction(parameter = 5) { // number}
var myString = 'Hellow World'; // stringvar myBool = true; // booleanvar myNumber = 1.23; // numbervar myExampleClass = new ExampleClass(); // ExampleClassvar myStringArray = ['hello', 'world']; // string[]
var anotherBool = myBool; // boolean
The compiled code in JavaScript
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Code sample #9 – Inferred Any Type
The compiled code in JavaScript
var example; // any
example = 'string'; // still any
Code sample #10 – Inferred Any Type
function example (myBool: boolean) { // any
if (myBool) {
return 'hello'; // string
}
return 1; // number
}
There will be no JavaScript code since there is a conflict with returned type.
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Code sample #11 – Contextual Typing Type inference uses a widened type when the initial value of a
variable, parameter, or function return value is deemed to be
null or undefined. In these cases, the dynamic any type is
used.
Code sample #12 – Widened Types
var func: { (param: number): number; };
func = function (a) { // a is inferred to be number,
// based on the type declaration
// of the func variable.
return a++;
}
var a = undefined; // any
var b = null; // any
var c = [null, null]; // any[]
var d = { a: undefined; b: 1 }; // { a: any; b: number }
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
If you are writing a large-scale application, you can nest your
modules just like you nest namespaces in .Net.
The aim should be to make the components of your program easy
to discover using autocompletion. For a discussion on Modules I
will name the program Succinctly and the first module
Utilities.
Code sample #13 – Utilities Module
Declaring a Module
module Sunccinctly {
module Utilities {
}
}
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
To add a class to a module, you use the class keyword. You can
then place variables and functions inside the class.
Code sample #14 – Logger Class (Utilities.ts)
Adding a Class to a Module
module Utilities {export class Logger {
log(message: string):void {if (typeof window.console !== 'undefined') {
window.console.log(message);}
}}
}
Code sample #15 – Calling the Logger
///<reference path="Utilities.ts" />
Window.onload = function () {
var logger = new Utilities.Logger();
logger.log('Logger is loaded');
};
This gives you powerful code organization tools that closely
match those available in .NET - you can imagine what the entire
TypeScript program might look like:
• Utilities.Logger
• Utilities.Dates
• Messaging.Ajax
• Messaging.JsonConverter
• Messagin.XmlConverter
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Private FunctionsCode sample #16 – Private Function
module Utilities {export class Logger {
log(message: string): void {if (typeof window.console !== 'undefined') {
window.console.log(this.getTimeStamp() + '-' + message);}
}
private getTimeStamp(): string {var now = new Date();
return now.getHours() + ':' +now.getMinutes() + ':' +now.getSeconds() + ':' +now.getMilliseconds();
}}
}
Type safety, interfaces, and protection
of private variables and functions only
occurs at design time and compilation
time in TypeScript.
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
If you run the latest example, you will see
that the message is now prefixed with a
timestamp, but that the format isn’t quite
right: 15:39:1:767 - Logger is loaded. When
the hours, minutes, or seconds are less than
two digits, or when the milliseconds are less
than three digits, the value should be left-
padded with zeros to preserve the time
stamp format.
Static Functions
Code sample #17 – Static Function
module Utilities {export class Logger {log(message: string): void {
if (typeof window.console !== 'undefined') {window.console.log(this.getTimeStamp() + '-' + message);
}}
private getTimeStamp(): string {var now = new Date();return Formatter.pad(now.getHours(), 2, '0') + ':' +
Formatter.pad(now.getMinutes(), 2, '0') + ':' +Formatter.pad(now.getSeconds(), 2, '0') + ':' +Formatter.pad(now.getMilliseconds(), 3, '0');
}}
class Formatter {static pad(num: number, len: number, char: string): string {
var output = num.toString();while (output.length < len) {
output = char + output;}return output;
}}
}
Currently available only in this module since export keyword is omitted
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Static Functions
The compiled code in JavaScript
In JavaScript Formatter is exposedfor all, since in JavaScript there is no
Type Safety
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
// beforereturn Formatter.pad(now.getHours(), 2, '0') + ':' +
Formatter.pad(now.getMinutes(), 2, '0') + ':' +Formatter.pad(now.getSeconds(), 2, '0') + ':' +Formatter.pad(now.getMilliseconds(), 3, '0');
// afterreturn Formatter.pad(now.getHours()) + ':' +
Formatter.pad(now.getMinutes()) + ':' +Formatter.pad(now.getSeconds()) + ':' +Formatter.pad(now.getMilliseconds(), 3);
Code sample #18 – Default Parameters
Default Parameters
Code sample #19 – Calling a function that has default parameters
// beforestatic pad(num: number; len: number, char: string) {
// afterstatic pad(num: number; len: number = 2, chart: string = '0') {
This new declaration do not affect the compiled JavaScript
code. It is useful for TypeScript code validation and tooltip.
Using an equal sign after type declaration you assign default value
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Code sample #20 – Optional Parameters
Optional Parameters
static pad(num: number, len: number = 2, char?: string) {
if (!char) {char = '0';
}}
Here I check for presence of argumentusing If block, and set value if it wasn't
passed (like default value)
The compiled code in JavaScript
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Rest Parameters
Code sample #21 – Rest Parameters
function addManyNumbers(…numbers: number[]) {var sum = 0;for (var i = 0; i < numbers.length; i++) {
sum += numbers[i];}return sum;
}
var result = addManyNumbers(1,2,3,5,6,7,8,9); // 41
The compiled code in JavaScript
Code sample #22 – Mixed Normal and Rest Parameters
function addManyNumbers(name: string, …numbers: number[]) {
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Function Overloads
To illustrate one potential use for function
overloads, imagine that the pad function could be
called either with a string to pad, or a number to
pad.
Code sample #22 – Function Overloads
static pad(num: number, len?: number, char?: string);static pad(num: string, len?: number, char?: string);static pad(num: any, len: number = 2, char: string = '0'): string {
var output = num.toString();while (output.length < len) {
output = char + output;}return output;
}
The compiled code in JavaScript
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Function Overloads
Code sample #23 – Default Parameters
// beforestatic pad(num: number; len: number, char: string) {
// afterstatic pad(num: number; len: number = 2, chart: string = '0') {
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Function Overloads
Code sample #24 – Alternative to Function Overloads
The compiled code in JavaScript
static padNumber(num: any, len?: number, char?: string): string {return padString(num.toString(), len, char);
}
static padString(input: string, len: number = 2, char: string = '0'): string {var output = input;while (output.length < len) {
output = char + output;}return output;
}
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
ConstructorsCode sample #25 – Constructor
export class Logger{constructor (private formatter: Formatter) {}
log(message: string): void {if (typeof window.console !== 'undefined') {
window.console.log(this.getTimeStamp() + ' – ' + message);}
}
private getTimeStamp(): string {var now = new Date();
return this.formatter.pad(now.getHours()) + ':' +this.formatter.pad(now.getMinutes()) + ':' +this.formatter.pad(now.getSeconds()) + ':' +this.formatter.pad(now.getMilliseconds(), 3);
}}
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Constructors
The compiled code in JavaScript
To create an instance of the Logger class, you are required
to pass in a Formatter. The development tools and
compiler will check that you do.
Code sample #26 – Calling a Constructor
var formatter = new Utilities.Formatter();var logger = new Utilities.Logger(formatter);
Remember, you will need to add the export keyword
to the formatter.
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Interfaces
Interfaces declared using the interface keyword and you
can make an interface available outside of a module using the
export keyword, just as you can with a class.
Code sample #27 – Ilogger Interface
export interface ILogger {
log(message: string): void;
}
Code sample #28 – Implementing Ilogger Interface
export class Logger implements ILogger {
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Interfaces
Code sample #30 – New Logger Class implementing multiple interfaces
Code sample #29 – New Logger Class
export class AnnoyingLogger implements ILogger {
log(message: string): void {
alert(message);
}
}
Multiple Interfaces
In TypeScript a class can implement more than one interface. To
do this, separate each interface with a comma:
export class MyClass implements IFirstInterface, ISecondInterface {
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Duck Typing
Code sample #31 – Duck Typing
interface IPerson {firstName: string;lastName: string;
}
class Person implements IPerson {constructor(public firstName: string, public lastName: string) {}
}
var personA: IPerson = new Person('Jane', 'Smith'); // explicitvar personB: IPerson = { firstName: 'Jo', lastName: 'Smith' }; // duck typing
function printName(personObj: IPerson) {console.log(personObj.firstName);
}
It is worth pointing out that the
type-checker doesn't require that
these properties come in any sort of
order, only that the properties the
interface requires are present and have
the required type.
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Inheritance and Polymorphism
Code sample #32 – Inheritance and Polymorphism
export class AnnoyingLogger extends Logger {
log(message: string): void {
alert(message);
super.log(message);
}
}
To inherit from a class, you use the extends keyword. The log
function alerts the user before calling the base Logger class,
which you can access with the super keyword. The result of
this function is that an alert dialog will be displayed, and when
it is closed, a message will be added to the console, if one is
running.
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Inheritance and Polymorphism
Code sample #33 – Calling the Logger
///<reference path='Utilities.ts'/>
window.onload = function () {
var logger: Utilities.ILoggeer = new Utilities.AnnoyingLogger();
Logger.log('Logger is loaded');
}
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Code sample #34 – Interface InheritanceMultiple Inheritanceinterface IMover {
mover() : void;}
interface IShaker {shake() : void;
}
interface IMoverShaker extends IMover, IShaker {}
class MoverShaker implements IMoverShaker {mover() {}
shake() {}
}
Because the IMoverShaker interface inherits from both IMover and
IShaker, the class must implement both the move function and the
shake function. This is a powerful feature that allows you to compose a
number of interfaces into a super interface.
A class can only inherit from one other class; it is not possible
to inherit from multiple classes
One interesting feature that TypeScript has that you won’t find in
.NET is the ability for an interface to inherit from another interface. Just
like class inheritance, you use the extends keyword to do this. Rather
than attempting to override or extend the behavior of a base class, you
would use interface inheritance to compose interface groups. Unlike
classes, interfaces can inherit from multiple interfaces.
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Super Inheritance
Figure #3 A Super Interface
The super interface in this diagram is the
IAmphibian interface. A class that implements this
super interface can do everything shown on the
right-hand side of the diagram. Without the super
interface, it would be hard to express that a class
needed both IBoat and ICar interfaces to be valid
for a given operation.
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Code sample #35 – Instance Of
Using instanceof
The instanceof keyword can be used to compare an
instance to a known type. It will return true if the instance is of
the known type, or inherits from the known type. For
example, the AnnoyingLogger class is an instance of
AnnoyingLogger, and it is also an instance of Logger.
var isLogger = logger instanceof Utilities.Logger; // true
var isLogger = logger instanceof Utilities.AnnoyingLogger; // true
var isLogger = logger instanceof Utilities.Formatter; // false
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
There are different ways of packaging your program depending
on where you are planning on running it. It is easier if you
decide on your packaging strategy up front as it may lead to a
subtly different program structure. So far I have used examples
that suit the first of the packaging techniques: bundling. This is
the technique you are most likely to use if you are writing
applications using ASP.NET MVC (bundling was introduced in
version 4).
The main differences packages can make to you TypeScript
program are:
• Module declaration style
• Module reference style
• Script loading style
I will describe how to do these three thing for each of the
packaging techniques here.
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Module Declaration Style
To use a bundling strategy in your program, you can declare the
modules as you have seen in the examples in this book.Code sample #37 – Main.ts
Code sample #36 – MyModule.ts
Module Referencing Style
module MyModule {
export class MyClass {
}
}
/// <reference path="MyModules.ts" />
var myClass = new MyModule.MyClass();
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Script Loading Style
Code sample #38 – BundleConfig.cs
public class BundleConfig{
public static void RegisterBundles(BundleCollection bundles){
bundles.Add(new ScriptBundle("~/MyProgram").Include("~/Scripts/MyModule.js", "~/Scripts/Maing.js"));}
}
If you want to include all scripts in a given directory, you can use a
wildcard character in your bundle registration, although this will not
guarantee any ordering like an explicit bundle would.
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Script Loading Style
Code sample #39 – Bundle Using Wildcard Character
public class BundleConfig
{
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new ScriptBundle("~/bundles/MyProgram").Include("~/Scripts/*"));
}
}
Code sample #40 – Using the Bundle
@Script.Render("~/bundles/MyProgram")
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
CommonJS is intended to provide a common standard library for JavaScript that makes it
easier to run as a server-side language, command-line tool, or desktop application. The
most famous implementation of CommonJS is the highly scalable Node.js, which runs on
Google’s V8 JavaScript engine.
http://www.commonjs.org/
If you are targeting a platform such as Node.js, which implements a CommonJS runtime
module loader, you can tell the TypeScript compiler to generate code that works out of the
box with CommonJS. To do this, add a module switch to the TypeScript compiler command
in your project file.
<Exec Command=""$(PROGRAMFILES)\Microsoft SDKs\TypeScript\tsc" --
module commonjs @(TypeScriptCompile ->'"%(fullpath)"', ' ')" />
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Code sample #41 – MyModule.ts
Module Declaration Style
export class MyClass {
}
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Code sample #42 – Main.ts
Module Reference Style
import myModule = module('MyModule'); // MyModule.ts
var myClass = new myModule.MyClass();
Script Loading Style
All of the scripts required by your Main.js file will be automatically
loaded by the CommonJS library.
Summary
TypeScript’s CommonJS support is tailored for platforms such
as Node.js, although there are many more implementations
that you may not have heard of, such as Narwhal and
CouchDB.
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
AMD stands for Asynchronous Module Definition and is an API that allows your modules
to be loaded asynchronously on an as needed basis. This is actually a pattern adapted
from CommonJS intended to be used in web browsers.
To use AMD, you will need to add a module-loader to your program, such as RequireJS.
http://requirejs.org/
To get AMD output from the TypeScript compiler, set the module mode to “amd” in your
project file.
<Exec Command=""$(PROGRAMFILES)\Microsoft SDKs\TypeScript\tsc" --
module amd @(TypeScriptCompile ->'"%(fullpath)"', ' ')" />
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Code sample #43 – MyModule.ts
Module Declaration Style
export class MyClass {
}
Code sample #44 – Main.ts
Module Reference Style
import myModule = module('MyModule'); // MyModule.ts
var myClass = new myModule.MyClass();
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Script Loading Style
<script src="Scripts/require.js" data-main="Scripts/Main"></script>
Specify your main program file
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
If you are designing a program that will run on the server, as well as in a browser, you can
write your modules in the CommonJS style, and use the TypeScript compiler to give you the
CommonJS and the AMD flavors of compiled JavaScript without having to change your code.
While your TypeScript remains unchanged between the two platforms, the CommonJS
output will use the built-in require function, while the AMD output will call RequireJS.
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Code sample #45 – Simple Ambient Declaration
declare var externalLogger;
externalLogger.anything();
Code sample #46 – Ambient Class Definition
declare class ExternalLogger {log(message: string): void;
}
declare var externalLogger: ExternalLogger;
externalLogger.anything();
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Code sample #47 – Ambient Class Definition
declare module ExternalUtilities {export class ExternalLogger {
public totalLogs: number;log(message: string): void;
}}
var externalLogger = new ExternalUtilities.ExternalLogger();
externalLogger.log("Hello World");var logCount = externalLogger.totalLogs;
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
You can place your ambient declaration in a separate file. If you do so, you should use a .d.ts file extension, for example,
ExternalLogger.d.ts. This file can then be referenced or imported just like any other TypeScript file.
Code sample #48 – Referencing Ambient Declaration File
/// <reference path="ExternalLogger.d.ts" />
var externalLogger = new ExternalUtilities.ExternalLogger();
externalLogger.log("Hello World");
externalLogger.anything();
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Figure #3 A Super Interface
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Open Visual Studio 2013
Open Tools menu Extensions and Updates… sub menu and follow the steps described in following image
You can also download this file directly from TypeScript Language website at http://www.typescriptlang.org/
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Installing the extension adds TypeScript language support to the Visual Studio. Now there is a support for new Project Type and File Templates.
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.
Adding TypeScript File to the Solution.
Right click on the Solution in Solution Explorer window, Select Add and from sub-menu select TypeScript File as seen in image.
This document contains proprietary and confidential information and may not be copied or distributed without the permission of Winston Levi.