Skip to main content

Getting started with TypeScript

  • Alternative to JavaScript
  • Allows us to use strict types
  • Supports modern features (arrow functions, let, const etc)
  • Extra features (generics, interfaces, tuples etc)
  • TypeScript are compiled to JavaScript ( the browser does not understand TypeScript )

Installing TypeScript#

npm i -g typescript

Compiling TypeScript#

tsc app.ts

On Windows you might have to add %APPDATA%\npm to you path environment variable if you get a tsc not found error.

To continuously watch the ts file for changes you can add the -w flag.

tsc app.ts -w

Create Typescript config file#

tsc --init

Type Basics#

// TypeScript infers the type automatically
let var1 = "I love TypeScript";
// Trying to reassign a variable to a different type will result in an error
var1 = 23; // Type '23' is not assignable to type 'string'
// For functions we need to explicitly define the input type
const result = (num1: number) => {
return num1 * 2;
};
console.log(result(23));

Objects and Arrays#

// arrays
let names = ["luigi", "mario", "yoshi"];
// this works as expected
names.push("toad");
// this doesn't work, because the array was declared with string only
names.push(45); // Argument of type '45' is not assignable to parameter of type 'string'.
let mixedarray = ["jean", 36, true];
// all of the below works because we declared a mixed array
mixedarray.push("melanie");
mixedarray.push(10);
// objects
let ninja = {
name: "mario",
belt: "black",
age: 30,
};
// Properties of the same type can be reassigned
ninja.name = "jean";
ninja.belt = "white";
// but you can reassign a different type
ninja.age = "36"; // Type '"36"' is not assignable to type 'number'
// You also can't add properties
ninja.skills = "kicking"; // Property 'skills' does not exist on type '{ name: string; belt: string; age: number; }'
// You also can reassign ninja to a different type
ninja = []; // Type 'undefined[]' is missing the following properties from type '{ name: string; belt: string; age: number; }': name, belt, age

Explicit Types#

// explicit types
// Declare varialbe for future use
let character: string;
let age: number;
let isLoggedin: boolean;
// We can only assign a value of the explicity declared type.
age = "36"; // Will not work, wrong type
age = 36;
isLoggedin = 34; // Will not work, wrong type
isLoggedin = true;
// arrays
let ninja: string[] = [];
// We can only push strings
ninja.push("jean", "john");
// If we want to push different types on to the array we need to use union types
// union types
let mixed: (string | number)[] = [];
mixed.push("jean", 36); // Works fine
// can do this
mixed.push("jean", 36, true); // booleans not allowed
// unions on normail variables
let uid: string | number;
uid = "12234";
uid = 567;
uid = true; // won't work
// object
let ninjaOne: object;
ninjaOne = {
name: "jean",
age: 36,
};
let ninjaTwo: {
name: string,
age: number,
belt: string,
};
ninjaTwo = {
name: "jean",
age: 36,
belt: "black",
};

Dynamic (any)#

// the any type basically remove all the type checking
let age: any;
// variable can be reassign to any type
// these are all valid
age = true;
age = "36";
age = 36;
// arrays
let mixed: any[] = [];
// valid for any type
mixed.push(20, "45", true);
// objects
let ninja: { name: any, age: any };
// valid assignments
ninja = { name: "jean", age: "25" };
ninja = { name: 36, age: "25" };

Functions#

// void functions that don't return anything
const add = (a: number, b: number, c: number = 10) => {
console.log(a + b + c); // 18
};
add(3, 5);
// You can optionally specify the return type, void
const add2 = (a: number, b: number, c: number = 10): void => {
console.log(a * b * c);
};
// return type function
const minus = (a: number, b: number) => {
return a * b;
};
minus(10, 3); // 7
// You can optionally specify the return type, number
const minus2 = (a: number, b: number): number => {
return a * b;
};

Type Aliases#

const greet = (user: { name: string, age: number }) => {
console.log(`Hello ${user.name}, I see you are ${user.age} years old`);
};
// we can recreate the above function to use a type alias
type user = { name: string, age: number };
const greet2 = (user: user) => {
console.log(`Hello ${user.name}, I see you are ${user.age} years old`);
};
// And it can be reused in multiple functions
const greetAgain = (user: user) => {
console.log(`Hello ${user.name}, happy birthday!`);
};

Function Signature#

// Example1
//signature
let greet: (a: string, b: string) => void;
// Function
greet = (name: string, greeting: string) => {
console.log(`${name} sasy ${greeting}`);
};
// Example 2
//signature
let calc: (a: number, b: number, c: string) => number;
// Function
calc = (numOne: number, numTwo: number, action: string) => {
if (action === "Add") return numOne + numTwo;
return numOne - numTwo;
};
// Example 3
type person = { name: string, age: number };
//signature
let logDetails: (obj: person) => void;
// Function
logDetails = (ninja: person) => {
console.log(`${ninja.name} is ${ninja.age} years old`);
};

The DOM and Type Casting#

// Selecting the form element via the class
const form = document.querySelector(".new-item-form") as HTMLFormElement;
// inputs
const type = document.querySelector("#type") as HTMLSelectElement;
const tofrom = document.querySelector("#tofrom") as HTMLInputElement;
const details = document.querySelector("#details") as HTMLInputElement;
const amount = document.querySelector("#amount") as HTMLInputElement;
// Eventlistener
form.addEventListener("submit", (ev: Event) => {
ev.preventDefault();
console.log(type.value, tofrom.value, details.value, amount.valueAsNumber);
});

Classes#

//classes
class Invoice {
constructor(
readonly client: string, // can not be modified internally or externally
private details: string, // can not be modified outside of class
public amount: number // can be modified outside of class
) {}
format(): string {
return `${this.client} owes $${this.amount} for ${this.details}`;
}
}
// create instance of the class
const invOne = new Invoice("Mario", "work on new site", 300);
const invTwo = new Invoice("Jean", "work on new site", 400);
// Creating an array of invoices
let invoices: Invoice[] = [];
invoices.push(invOne, invTwo);
invoices.forEach((inv) => {
console.log(inv.client, inv.amount, inv.format());
});

Interfaces#

Allows us to enforce a certain structures for classes and objects.

Basic example

// interface
interface IsPerson {
name: string;
age: number;
speak(a: string): void;
spend(a: number): number;
}
// This me variable must implement the IsPerson structure
const me: IsPerson = {
name: "Jean",
age: 36,
speak(text: string): void {
console.log(text);
},
spend(amount: number): number {
return 30;
},
};
// create a function that expects a value of type IsPerson
const greetingPerson = (person: IsPerson) => {
console.log(person);
};
greetingPerson(me);

with classes

// Create interface
export interface IInvoice {
format(): string;
}
// Then implement the class with the interface
import { IInvoice } from "../interfaces/IInvoice.js";
export class Invoice implements IInvoice {
constructor(
readonly client: string, // can not be modified internally or externally
private details: string, // can not be modified outside of class
public amount: number // can be modified outside of class
) {}
format(): string {
return `${this.client} owes $${this.amount} for ${this.details}`;
}
}

Generics#

Reusable blocks of code that can be used with different types

const addUID = (obj: object) => {
let uid = Math.floor(Math.random() * 100);
return { ...obj, uid };
};
const addUID = <T extends object>(obj: T) => {
let uid = Math.floor(Math.random() * 100);
return { ...obj, uid };
};
const addUID = <T extends { name: string }>(obj: T) => {
let uid = Math.floor(Math.random() * 100);
return { ...obj, uid };
};
let docOne = addUID({ name: "yoshi", age: 40 });
let docTwo = addUID("shaun");
console.log(docOne.name);
// with interfaces
interface Resource<T> {
uid: number;
resourceName: string;
data: T;
}
const docThree: Resource<object> = {
uid: 1,
resourceName: "person",
data: { name: "shaun" },
};
const docFour: Resource<string[]> = {
uid: 1,
resourceName: "shoppingList",
data: ["bread", "milk"],
};

Enums#

Allows us to create a constant set of items and associate them with a numeric value

enum ResourceType {
BOOK,
AUTHOR,
FILM,
DIRECTOR,
}
interface Resource<T> {
uid: number;
resourceType: ResourceType;
data: T;
}
const docOne: Resource<object> = {
uid: 1,
resourceType: ResourceType.BOOK,
data: { title: "name of the wind" },
};
const docTwo: Resource<object> = {
uid: 10,
resourceType: ResourceType.DIRECTOR,
data: { title: "name of the wind" },
};

Tuples#

Like arrays, but the types of data in each position is fixed once initialized.

let arr = ["ryu", 25, true];
arr[0] = false;
arr[1] = "yoshi";
arr = [30, false, "yoshi"];
let tup: [string, number, boolean] = ["ryu", 25, true];
tup[0] = false; // no allowed
tup[0] = "ken"; // allowed
let student: [string, number];
student = [23564, "chun-li"]; // no allowed
student = ["chun-li", 23564]; // allowed
Last updated on