Typescript

What is it for?

  • it adds types to Javascript
  • statically analysable code
  • IDE autocompletion support
  • easy refactoring
  • type correctness

What's different?

  • .ts file extension instead of .js
  • compiled
  • needs type definitions
    for using external libraries

Install typescript

sudo npm install -g typescript

Initialize typescript 

tsc --init

tsconfig.json

  • configuration for typescript compiler
  • for node use "target"="es6"

Typescript hello world

  • create index.ts
  • console.log('Hello world')
  • run tsc

So... where are those types?

Basic types

  • boolean
  • number
  • string
  • array
  • any
  • unknown
  • null, undefined
  • void, never

How to use them?

let myNumericVariable: number = 5;

let myString: string = 'hello';

let myArray: string[] = ['hello', 'hi'];
let myArray: Array<string> = ['hello', 'hi'];

And in functions...

function convertToUppercase(input: string): string {
    return input.toUpperCase();
}

function createPerson(id: number, firstName: string, lastName: string): {id: number, name: string} {
    return {
        id,
        name: `${firstName} ${lastName}`,
    };
}

Let's make a calculator

  • initialize and configure typescript
  • implement functions for:
    • addition
    • subtraction
    • sum of numbers in array

Modules

Modules in typescript

  • similar to nodejs modules
  • export
  • import
  • but different syntax

Export

import { calculateSum } from './my-file';

let result: number = calculateSum([1,2,3])

Import

export function calculateSum(numbers: number[]): number {
    return numbers.reduce((a, b) => a + b)
}

Export default

import renamedSum from './my-file';

let result: number = renamedSum([1,2,3]);

Import

export default function calculateSum(numbers: number[]): number {
    return numbers.reduce((a, b) => a + b)
}
  • only one default export per module

Try it out

  • move calculation functions to separate file (calculations.ts)
  • use import/export
  • create const for PI = 3.14 to a pi.ts and export it as default export

Importing node libraries

const lodash = require('lodash');

// becomes now:

import lodash from 'lodash';

You will also need type definitions for lodash

What is type definition?

Let's use lodash in Typescript

  • create array of people with id and name
  • use lodash.find to find person by id
  • initialize and configure typescript
  • npm install @types/lodash --save-dev

 

const people = [
    {
        id: 1,
        name: 'Peter'
    },
    {
        id: 2,
        name: 'Rachel'
    },
    {
        id: 3,
        name: 'John'
    },
    {
        id: 4,
        name: 'Tim'
    },
    {
        id: 5,
        name: 'Zed'
    }
];

How about person object?

const people = [
    {
        id: 1,
        name: 'Peter'
    },
    {
        id: 2,
        name: 'Rachel'
    },
    {
        id: 3,
        name: 'John'
    },
    {
        id: 4,
        name: 'Tim'
    },
    {
        id: 5,
        name: 'Zed'
    }
];

Let's define Person

interface Person {
    id: number;
    name: string;
}

Interface

  • describes the shape of object
  • no implementation
  • not included in transpiled code
interface Person {
    id: number;
    name: string;
    age?: number;
    shoutOnSomebody(name: string): string;
}
function createPerson(id: number, firstName: string, lastName: string)
    : {id: number, name: string} {
    return {
        id,
        name: `${firstName} ${lastName}`,
    };
}

// becomes this:

interface Person {
    id: number;
    name: string;
}

function createPerson(id: number, firstName: string, lastName: string): Person {
    return {
        id,
        name: `${firstName} ${lastName}`,
    };
}

Use Person as return type

Known type under any property

interface Person {
    name: string;
    age: number;
}

interface RandomKeys {
    [key: string]: Person
}

let item: RandomKeys = {
    martin: {
        name: 'Martin',
        age: 32
    },
    homer: {
        name: 'Homer',
        age: 50
    }
}

console.log(item.martin.name)
console.log(item['martin'].name)

Describe a function

interface PrintFunction {
    (text: string): void;
}

let printer: PrintFunction;
printer = (text) => console.log(text)
printer = (text) => console.error(text)

Interfaces excercise

  • define interface for a calculator
    • add(a, b) → number
    • subtract(a, b) → number
    • PI = 3.14
  • create an object which fits such interface
let calculator: Calculator = {...}

Classes

  • same as ES6 classes
  • encapsulate behaviour
class Animal {
    name: string;

    constructor(name: string) {
        this.name = name;
    }

    sayName() {
        console.log(`My name is ${this.name}`);
    }
}

Constructor shortcut

  • defines property right in the constructor
class Animal {
    constructor(public name: string) {
    }

    sayName() {
        console.log(`My name is ${this.name}`);
    }
}

Usage

let dog = new Animal('Lassie');
let mouse = new Animal('Mickey');

dog.sayName();
mouse.sayName();
  • we create instance of class

Class inheritance

  • class may inherit properties and methods from another class
  • parent class should be always more general
class Dog extends Animal {

    constructor(name: string) {
        super(name);
    }

    bark() {
        console.log(`Bark!`);
    }
}

public / private / protected

  • for both properties and methods 
  • limits access from outside
  • public
    • is default
    • everything may access the property
  • private
    • accessible only from the class
  • protected
    • accessible only from class and its derived classes

Let's describe an army

  • soldier with sword and shield
  • archer with a bow
  • knight on a horse with sword
  • everyone has some coordinates [X, Y]
  • abilities
    • use weapons
    • move

Union type

let value: number | string = 5; // ok
value = 'hi'; // also ok

let pet: Dog | Turtle | Cat;

Types

Type

  • you can define your own types
  • similar to interface
  • interface describes object-like stuff
  • type can use also primitive types
type Answer = 'yes' | 'no';

let x: Answer;

type Person = {
    name: string;
    age: number;
}

type AnswerList = {
    [key in Answer]: boolean;
}

Type

  • work with primitive types
  • more flexible (union etc)
  • sometimes don't appear in error messages

Interface

  • redefinition extends
  • for object types
  • always appear with original name in error messages

Generics

let value: Array<number> = [5, 2, 4];

// generic function
function print<T>(item: T) {
    console.log(item);
}
print<string>('hi');
let x = print(4);

Create generic class

class Bucket<T> {
  items: T[] = [];

  insert(item: T) {
    this.items.push(item);
  }
}

let myBucket = new Bucket<string>();
myBucket.insert('hello');

Partial generic class

interface Person {
    age: number;
    name: string;
}

let obj: Partial<Person> = {
    age: 32
}

Create a map

  • store data under keys
  • methods
    • set(key, value)
    • get(key)
    • has(key)
    • entities() - gives all keys
    • print() - prints everything inside the map

Decorators

@Component({
    selector: 'app-home',
    template: '<h1>Hello</h1>'
})
class HomeComponent {
}
  • not part of JS yet (stage 2)
  • adds metadata

Debugging

Debug typescript in VS Code

  1. enable "sourceMap": true in tsconfig.json
  2. switch to debug panel
  3. hit the settings icon - launch.json opens
  4. press Add Configuration
  5. choose Node.js: Launch Program
  6. set "program" property to index.ts
{
  "type": "node",
  "request": "launch",
  "name": "Launch Program",
  "program": "${workspaceRoot}/index.ts",
  "outFiles": [
    "${workspaceRoot}/**/*.js"
  ]
}

Alpiq Typescript

By Martin Nuc

Alpiq Typescript

  • 281