{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"sourceMap": true,
"lib": ["ESNext", "DOM"],
"moduleResolution": "node",
"outDir": "js",
"noImplicitAny": true
}
}
{
"version": "2.0.0",
"tasks": [
{
"type": "typescript",
"tsconfig": "tsconfig.json",
"option": "watch",
"problemMatcher": [
"$tsc-watch"
],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
cmd/ctrl + shift + b' to run
function greet(name:string):string {
return `Hello ${name}`;
}
greet('James');
index.ts
function greet(name) {
return "Hello " + name;
}
greet('James');
index.js
type Vehicle = Truck | Car
let myVehicle: Vehicle = obtainRandomVehicle()
// The exhaustive conditional
if (myVehicle instanceof Truck) {
myVehicle.tow() // Truck
} else if (myVehicle instanceof Car) {
myVehicle.drive() // Car
} else {
// NEITHER!
const neverValue: never = myVehicle
}
let str = 'hello';
str = 2; // ERROR
// Variables
let str: string;
str = 'hello'; // fine
str = 2; // ERROR
// Functions
function logPerson(name: string, age: number): void {
console.log(`My name is ${name} and I am ${age} years old.`);
}
logPerson('James', 42); // fine
logPerson() // Errors (if struct null typing inforced)
Variables:
On Functions:
let str: string | number;
str = 'hello'; // fine
str = 2; // fine
str = true; // ERROR
The variable must hold one OR another type
You can have as many as you like
type MouseEvent = 'click' | 'dblclick' | 'mouseup' | 'mousedown';
type headsOrTailsResult = 'heads' | 'tails';
function flipCoin():headsOrTailsResult{
return Math.random() > 0.5 ? 'heads' : 'tails';
}
const result = flipCoin();
The variable must hold one OR another string
function getPetInsurance(pet: Animal & { chipId: string }):Insurance {
// Code here will deal with animal instances
// AND enhanced animal instances with chipIds
}
The variable can hold type A AND type B (rarely used)
You can only use the properties that both type A and type B possess
let nameInput = document.querySelector('#name') as HTMLInputElement;
When we change something's type:
let enteredText = (nameInput as HTMLInputElement).value;
let nameInput = document.querySelector('#name');
nameInput.value; // throws an error
We can use the as keyword:
or the <> operator:
let nameInput = <HTMLInputElement>document.querySelector('#name');
let nameInput = getVAT(200, 0.2, true) as string;
When we tell typescript what type an expression returns:
function getVAT(price:number, rate:number, format:boolean=false): number | string {
let netPrice = price * rate;
return format ? `£${netPrice}` : netPrice;
}
We can use the as keyword:
or the <> operator:
let nameInput = <string>getVAT(200, 0.2, true);
let nameInput = getVAT(200, 0.2, false) as number;
function padLeft(padding: number | string, input: string) {
if (typeof padding === "number") { // <-- Type guard
return " ".repeat(padding) + input;
}
return padding + input;
}
When we use defensive checks to ensure a type
type car = {
name: string
bhp: number
avatar_url?: string
}
let scores: number[] = [56, 34, 42];
// OR
// Generics syntax
let scores: Array<number> = [56, 34, 42];
enum People { 'Rod', 'Jane', 'Freddy'} // 0,1,2
enum People { 'Rod'=1, 'Jane', 'Freddy' } // 1,2,3
enum People { 'Rod'=1, 'Jane'=3, 'Freddy'=5 }
let favePersonId:People = People.Freddy;
console.log(favePersonId); // 5
let favePersonName = People[favePersonId];
console.log(favePersonName); // Freddy
let record: [number, string] = [2, 'James'];
let record: [number, string] = [2, 'James', false]; // Error
interface Person {
name: string,
age: number,
job?: string
}
let person:Person = {
name: 'James'
}; // Error: Property 'age' is missing in type
// Define an interface for your object
interface GreetingSettings {
duration: number;
color?: string;
}
const defaults = {
duration: 500,
color: '#000'
};
// Then use it
function greet(greeting: string, options: GreetingSettings = defaults, extra?: boolean): void {
// ...
}
greet('Hello Joe!!');
greet('Hello Wayne!!', { duration: 1000, color: '#f00'});
type numericFn = (num:number) => number; // type definition
let squareFn: numericFn = (n) => n*n;
console.log(squareFn(2));
function printSquare(this: Stat) { // if 'this' is unclear
return (this.value * this.value).toFixed(2);
}
interface Stat {
value: number;
square(): string; // defined on an interface
}
let myStat:Stat = {
value: 3,
square: printSquare
};
console.log(myStat.value);
console.log(myStat.square());
type decs are global and hoisted
function addNumbers(a: number, b: number): number {
return a + b;
}
function addStrings(a: string, b: string): string {
return a + b;
}
When types of the params determine the operation of the function
Can we union these 2 functions?
function add(a: number, b: number): number;
function add(a: string, b: string): string;
function add(a: any, b: any): any {
return a + b;
}
Yes we can!
class Person {
constructor(
public name: string,
public role: string,
public age: number
) {}
}
const mike = new Person("Mike Hawthorn", "CEO", 45)
“S” because it’s describing the type of a “S”tate.
function holder<T>(startingVals:Array<T>) {
return {
get():Array<T>{
return startingVals;
},
add(newVal:T):void {
startingVals.push(newVal)
}
}
}
const numHolder = holder([2]);
numHolder.get().toUppercase(); // <-- will error
const objHolder = holder([{ name: 'James', age: 44 }]);
objHolder.add({ name: 'Robert', }) // <-- will error
const inputForm = document.forms[0]! as HTMLFormElement; // Throw an error if you don't find
const nameInput = inputForm.querySelector('input#name') as HTMLInputElement;
const title = inputForm.querySelector('#title') as HTMLInputElement; // required because ambiguous
const personDisplay = document.getElementById('person-display') as HTMLParagraphElement;
interface PersonInterface {
name: string;
title?: string;
}
class Person implements PersonInterface {
constructor (public name: string, public title?: string) {}
getGreeting() {
return `Hi, my name is ${this.name}, ${this.title ? `I am the ${this.title}` : ''}.`;
}
}
inputForm.addEventListener('submit', (e) => {
e.preventDefault();
const person = new Person(nameInput.value, title.value);
personDisplay.textContent = person.getGreeting();
inputForm.reset();
})