Skip to content

Instantly share code, notes, and snippets.

@enricosoft
Created May 31, 2017 15:48
Show Gist options
  • Save enricosoft/74c0070a560a1ef2942d23689b77fa66 to your computer and use it in GitHub Desktop.
Save enricosoft/74c0070a560a1ef2942d23689b77fa66 to your computer and use it in GitHub Desktop.
Typescript Tutorial

TYPESCRIPT

** What is **

TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. It's developed by Microsoft. Right now the stable version is 2.3. It's used by the major frameworks like React, Angular, NodeJs express, ASP.NET, React Native, etc.

** Installation **

Visual Studio 2017 and Visual Studio 2015 Update 3 include TypeScript by default. Otherwise: npm install -g typescript

** Compiling your code **

Typescript file extension is .ts (for example: tsc greeter.ts)

You can compile it doing: tsc greeter.ts

The result will be a file greeter.js

** Particularity **

  1. Type annotations: they introduced the types for variables (like string, number, boolean, number[] or Array, [string, number], ecc). In this case if you assign a string value to a number variable the compiler will catch an error. Example:
var name: string = 'Enrico';  // OK
var name: string = 1;         // ERROR

There are 5 special types: any --> var power: any; // takes all variable value types

null \ undefined --> var num: number = null; // These literals can be assigned to anything

void --> function log(message): void {} // a function does not have a return type

never --> // is the return type for a function that always throws an exception or one that never returns

function error(message: string): never {
    throw new Error(message);
}

NOTA: use "let" instead of "var" during variable declaration Example: let myvar: string;

Use "const" for variable that must have immutable value const foo = 123;

Type assertion: there are 2 ways:

let someValue: any = "this is a string";
let strLength1: number = (<string>someValue).length;
let strLength2: number = (someValue as string).length;
  1. Enums: an enum is a way of giving more friendly names to sets of numeric values
enum Color {Red, Green, Blue}
let c: Color = Color.Green;

or with assigned values

enum Color {Red = 1, Green, Blue}
let c: Color = Color.Green;
  1. Interfaces: an interface is a particular class that describes an objects. Example:
interface Person {
    firstName: string;
    lastName: string;
}

// Consume (example 1)
function newPartecipant(person: Person): void{
	
}

// Consume (example 2)
var partecipant: Person;
partecipant = {
    firstName: 'John',
    lastName: 'Doe'
};
  1. Classes: support for class-based object-oriented programming. Every class will have a constructor and a few public fields. When you declare constructor arguments, if you use "public" keyword before the argument will allow Typescript to automatically create properties with that name.
class Student {
    fullName: string;
	
    constructor(public firstName, public middleInitial, public lastName) {
        this.fullName = firstName + " " + middleInitial + " " + lastName;
    }
}

// Consume
var user = new Student("Jane", "M.", "User");

It's possible also to extend a class (so you will inherit all its functions\properties)

class ExtendedAdder extends Adder {
	....
}
  1. Functions
function buildName(firstName: string, lastName = "Smith") : string {
    return firstName + " " + lastName;
}

As argument you can have also this variants:

lastName?: string // Optional parameter lastName = "Smith" // Assign default value

  1. Arrow function

This symbol is => "this" is a variable that’s set when a function is called. This makes it a very powerful and flexible feature, but it comes at the cost of always having to know about the context that a function is executing in. This is notoriously confusing, especially when returning a function or passing a function as an argument. The scope of Arrow functions is to replace the usage of "this". Arrow functions capture the this where the function is created rather than where it is invoked.

()=>something

  1. You don't need to keep typing function
  2. It lexically captures the meaning of this
  3. It lexically captures the meaning of arguments

For example this function increments a value X of 1 unity:

var inc = (x)=>x+1;

Altro esempio di utilizzo:

class Adder {
    constructor(public a: number) {}
    // This function is now safe to pass around
    add = (b: number): number => {
        return this.a + b;
    }
}
  1. Generics

A major part of software engineering is building components that not only have well-defined and consistent APIs, but are also reusable. Components that are capable of working on the data of today as well as the data of tomorrow will give you the most flexible capabilities for building up large software systems.

An example of a function that works with any type of data is the following:

function identity(arg: any): any {
    return arg;
}

in this case we don't used generics type. The problem is that using "any" we are LOSING the information about what that TYPE was when the function returns. The right way to write this generic function is the following:

function identity<T>(arg: T): T {
    return arg;
}

This T allows us to capture the type the user provides (e.g. number)

// Consume example
let output = identity<string>("myString");

The generic is applicable not only to function arguments but also to classes. For example:

class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };
  1. Symbol: a primitive data type

Symbol is introduced starting from ECMAScript 2015 and it is a primitive data type, just like number and string. Symbols are immutable, and unique so you can use it as ID\KEYS for object properties.

let sym = Symbol();

let obj = {
    [sym]: "value"
};
  1. Modules

Modules are executed within their own scope, not in the global scope; this means that variables, functions, classes, etc. declared in a module are not visible outside the module unless they are explicitly exported using one of the export forms.

Modules are declarative; the relationships between modules are specified in terms of imports and exports at the file level.

If you export a module, other modules will able to use it using keywords "implements"... For example:

// EXPORT

export interface StringValidator {
    isAcceptable(s: string): boolean;
}

export const numberRegexp = /^[0-9]+$/;

export class ZipCodeValidator implements StringValidator {
    isAcceptable(s: string) {
        return s.length === 5 && numberRegexp.test(s);
    }
}

// IMPORT

import { ZipCodeValidator } from "./ZipCodeValidator";

let myValidator = new ZipCodeValidator();
  1. Namespaces

To better organize the source code, instead of putting lots of different names into the global namespace, let’s wrap up our objects into a namespace. Example:

namespace Validation {
    export interface StringValidator {
        isAcceptable(s: string): boolean;
    }

    const lettersRegexp = /^[A-Za-z]+$/;
    const numberRegexp = /^[0-9]+$/;

    export class LettersOnlyValidator implements StringValidator {
        isAcceptable(s: string) {
            return lettersRegexp.test(s);
        }
    }

    export class ZipCodeValidator implements StringValidator {
        isAcceptable(s: string) {
            return s.length === 5 && numberRegexp.test(s);
        }
    }
}

// CONSUME

// 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();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment