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
- run node index.js
Where are 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
- when using multiple files
- export
- import
Named 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 libraries
import lodash from 'lodash';
lodash.without([1,2,3], 2);
- remember to install the library first!
You will also need type definitions for lodash
What is type definition?
- file containing description of all functions, classes and objects used in the library
- describes only shape, no implementation
- .d.ts extension
- https://github.com/DefinitelyTyped/DefinitelyTyped
- install it using:
- npm install @types/lodash --save-dev
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}`);
}
}
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
Constructor shorthand
- defines property right in the constructor
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
sayName() {
console.log(`My name is ${this.name}`);
}
}
class Animal {
constructor(public name: string) {}
sayName() {
console.log(`My name is ${this.name}`);
}
}
➡️ 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 Person = {
name: string;
age: number;
}
type Answer = 'yes' | 'no';
let x: Answer;
type AnswerList = {
[key in Answer]: boolean;
}
const list: AnswerList = {
yes: true,
no: false
}
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
Type guards
- tells the compiler true type
type Square = {
type: 'square';
size: number;
};
type Circle = {
type: 'circle';
radius: number;
};
type Shape = Square | Circle;
const shape: Shape = ...
if (isSquare(shape)) {
console.log(`Size is ${shape.size}`);
}
function isSquare(shape: Shape): shape is Square {
return shape.type === 'square';
}
typeof
- get type from data
const obj = {
id: 1,
name: 'Martin'
}
type Person = typeof obj;
const obj2: Person = {
id: 2,
name: 'Lukas'
}
keyof
- gets keys from an object type
const obj = {
id: 1,
name: 'Martin'
}
type Person = typeof obj;
// 'id' | 'name'
const key: keyof Person = 'id';
Intersection type
- combines multiple types
type Person = {
id: number;
name: string
}
type Developer = {
os: 'Linux' | 'macOS' | 'Windows';
}
const someone: Person & Developer = {
id: 5,
name: 'George',
os: 'Linux'
}
Generics
let value: Array<number> = [5, 2, 4];
// generic function
function print<T>(item: T) {
console.log(item);
return item;
}
print<string>('hi');
let x = print(4); // x will be of type number
Create generic class
class Bucket<T> {
items: T[] = [];
insert(item: T) {
this.items.push(item);
}
}
let myBucket = new Bucket<string>();
myBucket.insert('hello');
➡️ 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
Utility classes
Partial<>
interface Person {
age: number;
name: string;
}
let obj: Partial<Person> = {
age: 32
}
- makes all keys optional
Pick<>
interface Person {
age: number;
name: string;
height: number;
}
let obj: Pick<Person, 'age' | 'name'> = {
age: 32,
name: 'Martin'
}
- object with only certain keys
Omit<>
interface Person {
age: number;
name: string;
height: number;
}
let obj: Omit<Person, 'height'> = {
age: 32,
name: 'Martin'
}
- object without certain keys
Exclude<>
type Animal = Dog | Turtle | Shark;
let obj: Exclude<Animal, Turtle>
// obj: Dog | Shark
- disallows certain type
Parameters<>
type AdditionFn = (a: number, b: number): number;
type Params = Parameters<AdditionFn>; // [number, number]
function add(a: number, b: number): number {
return a + b;
}
type Param = Parameters<typeof add>; // [number, number]
- for function parameters
Conditional type
type Coords3d = {
x: number;
y: number;
z: number;
};
type Coords2d = {
x: number;
y: number;
};
type Sphere = {
coords: Coords3d;
};
type Circle = {
coords: Coords2d;
};
type Shape = Sphere | Circle;
function placeRandomly<T extends Shape>(
shape: T
): T extends Sphere ? Coords3d : Coords2d {
...
}
placeRandomly({ coords: { x: 1, y: 2 } });
➡️ Create type
- for a function which removes key from object
- inputs:
- object
- key to be removed
- output
- object without the key
function removeKey(obj, key) {
const duplicate = { ...obj };
delete duplicate[key];
return duplicate;
}
Decorators
@Component({
selector: 'app-home',
template: '<h1>Hello</h1>'
})
class HomeComponent {
}
- not part of JS yet (stage 2)
- adds metadata
- modifies what follows on next line
Tieto Typescript
By Martin Nuc
Tieto Typescript
- 187