Installing typescript
npm install -g typescript
Transpile command
tsc ./filepath.ts
Watch file changes
tsc -w ./filepath.ts
Add a file called "tsconfig.json":
{
"compilerOptions": {
"target": "es5"
}
}
If this file exists you can type:
tsc -w
and Typescript will know which files to compile
function countdown (initial, final = 0, interval= 1) {
var current = initial;
while (current > final) {
container.innerHTML = current
current-=interval;
}
}
Template literals are string literals allowing embedded expressions
var todo = {
id: 123,
name: "Pickup drycleaning",
completed: true
};
var displayName = `
<div todo="${todo.id}" class="list-group-item">
<i class="${todo.completed ? '': 'hidden'} text-success"></i>
<span class="name">${todo.name}</span>
</div>
`;
Let - Declare a block scope variable
for (var i = 0; i<=5; i++) {
let counter = i;
}
Const - Create a read-only reference to a value
const id = 'A8D76ASDADASD98';
Used to iterate iterable objects. Similar to the "For in" loop but iterates values instead of keys.
for (let value of array) {
console.log(value);
}
Use curly braces to group statements
var fn = (param1) => {
var square = param1 * param1;
return square;
}
If just one parameter is used you can write it without parenthesis. When only one statement is used that becomes the implicit return.
var fn = param 1 => param1*param1; //Returns param1*param1
If you want the function to return an object you need to use parenthesis.
var fn = param1 => ({value: param1*param1});
Assign values to multiple variables from a single object with a single statement.
ES6
var array = [123, 'Pickup drycleaning.', true];
var [id, title, completed] = array;
var todo = {
id: 123,
name: "Pickup drycleaning",
completed: true
};
var {id, name, completed} = todo;
ES5
var array = [123, 'Pickup drycleaning.', true];
var id = array[0], title = array[1], completed = array[2];
var todo = {
id: 123,
name: "Pickup drycleaning",
completed: true
};
var id = todo.id, title = todo.title, completed = todo.completed;
Usage example
function countdown ({
initial,
final: final = 0,
interval: interval = 1,
initial: current
}) {
while (current > final) {
container.innerHTML = current
current-=interval;
}
}
Can be used to expand an iterable object when multiple items are expected.
function calculate (action, ...values) {
var total = 0;
for (var value of values) {
switch (action) {
case 'add':
total+= values;
break;
case 'substract':
total-= values;
break;
}
}
return total;
}
console.log(calculate('substract', 100,50,25)); //25
var source = [4,5,6];
var target = [1,2,3,...source,7,8,9];
- boolean
- number
- string
- null / undefined
- object (functions, arrays, ...)
function totalLength (x: any[], y: string): number {
var total = x-length + y.length;
return total;
}
function totalLength (x: (string | any[]), y: (string | any[])): number {
var total = x-length + y.length;
x.slice(0);
if (x instanceof Array) {
x.push('abc');
}
if (x instanceof String) {
x.substr(1);
}
return total;
}
You can define the function to accept either two string parameters or two array parameters by overloadingthe function using the next syntax:
function totalLength (x: string, y: string): number
function totalLength (x: any[], y: any[]): number
function totalLength (x: (string | any[]), y: (string | any[])): number {
...
}
interfaces Todo {
name: string;
completed?: boolean; // The question mark makes the property optional
}
interface ITodoService {
add(todo: Todo): Todo;
delete(todoId: number): void; // Used when a function doesn't return anything
getAll(): Todo[]; // Returns an array of Todo objects
getById(todoId: number): Todo;
}
var todo: Todo = {
name: 'Pick up drycleaning'
};
interface jQuery {
(selector: string): HTMLElement;
version: number;
}
Casting syntax (type assertions) <jQuery>
forces typescript into treating the next function as an instance of jQuery interface no matter what type of data Typescript thinks the variable is.
var $ = <jQuery>function (selector) {
// Find DOM element
};
$.version = 1.12;
var element = $('#container');
For this you need to create a brand new interface that shares the same name as the one you want to extend.
interface jQueryElement {
data(name: string): any;
data(name:string, data: any): jQueryElement;
}
interface jQueryElement {
todo(): Todo;
todo(todo: Todo): jQueryElement;
}
Enums are a way to define a set of meaningful constant values.
interface Todo {
name: string;
state: TodoState;
}
enum TodoState {
New = 1, // All of the following members are auto-incremented from this point on
Active,
Complete,
Deleted
}
function delete (todo: Todo) {
if (todo.state !== TodoState.Complete) {
throw 'Can't delete incomplete task!';
}
}
var todo: Todo = {
name: 'Pick up drycleaning',
state: TodoState.New
};
var todo: { name: string };
function totalLength (x: { length: number }, y: {length: number}): number {
return x.length + y.length;
}
TS:
class TodoService {
constructor (private todos: Todo[]) {
}
getAll () {
return this.todos;
}
}
ES5:
var TodoService = (function () {
function TodoService (todos) {
this.todos = todos;
}
TodoService.prototype.getAll = function () {
return this.todos;
};
return TodoService;
})();
class TodoService {
static lastId: number = 0;
constructor (private todos: Todo[]) {
}
getAll () {
return this.todos;
}
}
interface Todo {
name: string;
state: TodoState;
}
enum TodoState {
New = 1, // All of the following members are auto-incremented from this point on
Active,
Complete,
Deleted
}
var todo: Todo = {
name: 'Pick up drycleaning',
get state () {
return this._state;
},
set state(newState) {
if (newState === TodoState.Complete) {
var canBeCompleted = this.state == TodoState.Active
|| this.state == TodoState.Deleted;
if (!canBeCompleted) {
throw 'Todo must be Active or Deleted in order to be marked as Completed';
}
}
this._state = newState;
}
};
todo.state = TodoState.Complete;
todo.state;
class SmartTodo {
_state: TodoState;
name: string;
get state () {
return this._state;
}
set state(newState) {
if (newState === TodoState.Complete) {
var canBeCompleted = this.state == TodoState.Active
|| this.state == TodoState.Deleted;
if (!canBeCompleted) {
throw 'Todo must be Active or Deleted in order to be marked as Completed';
}
}
this._state = newState;
}
constructor (name: string) {
this.name = name;
}
}
var todo = new SmartTodo('Pick up drycleaning');
todo.state = TodoState.Complete;
class TodoStateChanger {
constructor (private newState: TodoState) {}
canChangeState (todo: Todo): boolean {
return !!todo;
}
changeState (todo: Todo): Todo {
if (this.canChangeState(todo)) {
todo.state = this.newState;
}
return todo;
}
}
class CompleteTodoStateChanger extends TodoStateChanger{
constructor () {
super(TodoState.Complete); // Base class constructor.
}
canChangeState (todo: Todo): boolean {
// Super in this context is the base class object.
return super.canChangeState(todo) && (
todo.state == TodoState.Active
|| todo.state == TodoState.Deleted
);
}
}
Abstract classes are only defined in order to act as base classes and are not meant to be instantiated.
abstract class TodoStateChanger {
constructor (private newState: TodoState) {}
// Every derived class must implement it's own canChangeState method
abstract canChangeState (todo: Todo): boolean;
changeState (todo: Todo): Todo {
if (this.canChangeState(todo)) {
todo.state = this.newState;
}
return todo;
}
}
public
default modifierprivate
When a member is marked private, it cannot be accessed from outside of its containing class.protected
The protected modifier acts much like the private modifier with the exception that members declared protected can also be accessed by instances of deriving classes.
The primary reason interfaces exist in static languages is to attatch them to classes to make sure that they behave the way you expect them to. The way to do it is by using the implements
keyword.
interface Todo {
id: number;
name: string;
state: TodoState;
}
interface ITodoService {
add (todo: Todo): Todo;
getAll(): Todo[];
}
class TodoService implements ITodoService {
private static lastId: number = 0;
constructor (private todos: Todo[]) {}
get nextId () {
return TodoService.lastId += 1;
}
add (todo: Todo) {
var newId = this.nextId;
}
getAll () {
return this.todos;
}
}
Generics are a way to create components that can work over a variety of types rather than a single one.
function clone <T> (value: T): T {
let serialized = JSON.stringify(value);
return JSON.parse(serialized);
}
clone('Hello!'); // function clone<string>(value: string): string
clone(123); // function clone<string>(value: number): number
var array: number[] = [1, 2, 3];
var array2: Array<number> = [1, 2 , 3];
class KeyValuePair <TKey, TValue> {
constructor (
public key: TKey,
public value: TValue
) {}
}
let pair1 = new KeyValuePair <number, string> (1, 'First');
let pair2 = new KeyValuePair <string, Date> ('Second', new Date(Date.now()));
let pair3 = new KeyValuePair <number, string> (3, 'Third');
class KeyValuePairPrinter <T, U> {
constructor (private pairs: KeyValuePair<T, U>[]) {}
print () {
for (let p of this.pairs) {
console.log(`${p.key}: ${p.value}`);
}
}
}
var printer = new KeyValuePairPrinter([pair1, pair3]);
printer.print();
function totalLength <T extends { length: number }> (x: T, y: T) {
var total = x.length + y.length;
return total;
}
var length = totalLength('Jess', 'Roger');
interface IHaveALength {
length: number;
}
function totalLength <T extends IHaveALength> (x: T, y: T) {
var total = x.length + y.length;
return total;
}
var length = totalLength('Jess', 'Roger');