- bought on 10/01/2023
- start on 10/01/2023
- end on 10/16/2023
The introductory section covers basic TypeScript concepts and syntax.
This section explains the difference between var
and let
when declaring variables.
Demonstrates the usage of const
for creating constant variables in TypeScript.
const age: number = 40;
const result: string = `hello Mario (${age})`;
console.log(result); // Output: hello Mario (40)
Illustrates the usage of template literals, a powerful feature in ES6 javascript.
const age: number = 40;
const result: string = `hello Mario (${age})`;
console.log(result); // Output: hello Mario (40)
Introduces short object syntax and its implementation.
const user: { id: number, name: string, surname: string, profile: { color: string, location: string } } = {
id: 123,
name: 'Fabio',
surname: 'Biondi',
profile: {
color: 'black',
location: 'Trieste'
}
};
const { id, profile: { color } } = user;
const params: { id: number, color: string } = { id, color };
console.log(params); // Output: { id: 123, color: 'black' }
Demonstrates array destructuring using the spread operator ...
const list: number[] = [10, 20, 30, 40, 50];
const [a, b, ...rest]: number[] = list;
console.log(a, b, rest); // Output: 10 20 [30, 40, 50]
Covers object destructuring with default values.
const user2: { first: string, preference?: string } = {
first: 'Fabio',
preference: 'red'
};
const { first, preference: pref = 'black' }: { first: string, preference: string } = user2;
console.log(`${first} (${pref})`); // Output: Fabio (red)
Explains nested object destructuring and extracting values.
const user3: { name: string, profile: { color: string, location: { lat: number, lng: number } } } = {
name: 'Fabio',
profile: {
color: 'red',
location: {
lat: 15,
lng: 12
}
}
};
const { profile: { location: { lat, lng } } } = user3;
console.log(lat, lng); // Output: 15 12
Demonstrates renaming properties during object destructuring.
const { profile: { location: { lat: lt, lng: lg, zoom = 5 } } } = user3;
const params2: { lt: number, lg: number, zoom: number } = { lt, lg, zoom };
console.log(params2); // Output: { lt: 15, lg: 12, zoom: 5 }
Shows how to clone, merge, and modify arrays using the spread operator.
const data: number[] = [1, 2, 3, 4];
const list2: number[] = [5, 6];
const merged: number[] = [...data, ...list2, 7, 8];
console.log(merged); // Output: [1, 2, 3, 4, 5, 6, 7, 8]
Compares object cloning techniques using Object.assign
and the object spread operator.
const obj: { id: number, name: string } = {
id: 123,
name: 'Fabio'
};
const preferences: { color: string } = { color: 'red' };
const merged3: { id: number, name: string, color: string, pet: string } = { ...obj, ...preferences, pet: 'dog' };
console.log(merged3); // Output: { id: 123, name: 'Fabio', color: 'red', pet: 'dog' }
Introduces arrow functions and demonstrates their usage.
const addVariable = function addOperation(a: number, b: number): number {
return a + b;
}
const add = (a: number, b: number): number => a + b;
const divide = (a: number, b: number): number => a / b;
const pow = (a: number): number => a * a;
const greetings = (): void => console.log('hello');
greetings();
Explains the map
function for transforming array elements.
const users: { id: number, name: string, age: number, gender: string, city: string }[] = [
{"id": 10, "name": "Silvia", "age": 2, "gender": "F", "city": "Gorizia"},
{"id": 20, "name": "Fabio", "age": 40, "gender": "M", "city": "Trieste"},
{"id": 30, "name": "Lorenzo", "age": 6, "gender": "M", "city": "Pordenone"},
{"id": 40, "name": "Lisa", "age": 40, "gender": "F", "city": "Gorizia"}
];
const newList: string[] = users.map(user => `${user.name} (${user.age})`);
console.log(newList);
// Output: ["Silvia (2)", "Fabio (40)", "Lorenzo (6)", "Lisa (40)"]
Demonstrates how to filter array elements based on a condition.
const newList2: number[] = users.filter(user => user.age > 18).map(user => user.id);
console.log(newList2);
// Output: [20, 40]
Illustrates the usage of find
and findIndex
functions on arrays.
const ID: number = 30;
const index: number = users.findIndex(user => user.id === ID);
users.splice(index, 1);
console.log(users);
Explains the concept of immutability and its significance in various frameworks.
// ADD
const user4: { id: number, name: string } = { id: 50, name: 'Mario' };
let newRef: { id: number, name: string }[] = [...users, user4];
// DELETE
const ID2: number = 40;
newRef = users.filter(u => u.id !== ID2);
// EDIT
const updatedUser: { id: number, name: string, age: number } = { id: 20, name: 'Ciccio', age: 25 };
newRef = users.map(u => u.id === updatedUser.id ? { ...u, ...updatedUser } : u);
Explains the concepts of classes, inheritance, and lexical 'this'.
class Pippo {
// Class variables
text: string = 'Ciao';
// Constructor called at every new instance
constructor() {
setTimeout(() => {
console.log(this.text); // 'this.text' here is undefined due to the lexical 'this'
}, 2000);
}
// Class method
hello(value: string): void {
console.log(this.text + ' ' + value); // 'this' is used to access a class variable
}
}
const p: Pippo = new Pippo();
p.hello('Fabio');
// Inheritance
class Pluto extends Pippo {}
const pluto: Pluto = new Pluto();
pluto.hello('Fabio'); // Method inherited from Pippo
Covers module imports and usage in TypeScript.
export const exportedVar: number = 1;
export const addFunction = (a: number, b: number): number => a + b;
In HTML:
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ES6 Modules</title>
<script type="module" src="main.js"></script>
</head>
<body>
<!-- Content -->
</body>
</html>
In main.js:
// main.ts
import { exportedVar, addFunction } from './utility.js';
console.log(exportedVar); // Output: 1
console.log(addFunction(3, 4)); // Output: 7
In HTML:
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ES6 Modules</title>
<script type="module" src="main.js"></script>
</head>
<body>
<!-- Content -->
</body>
</html>
In main.js:
// main.ts
import { add } from './utility.js';
import { add as newAdd } from './operations.js'; // Using 'as' to rename the function
console.log(add(1, 4)); // Output: 5
console.log(newAdd(5)); // Output: 7
In HTML:
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ES6 Modules</title>
<script type="module" src="main.js"></script>
</head>
<body>
<!-- Content -->
</body>
</html>
In utility.js:
// utility.js
const add = (a, b) => {
return a + b;
};
export default add;
In main.js:
// main.ts
import add from './utility.js'; // Importing the default function
console.log(add(3, 4)); // Output: 7
In HTML:
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ES6 Modules</title>
<script type="module" src="main.js"></script>
</head>
<body>
<!-- Content -->
</body>
</html>
In main.js:
// main.ts
import { add, subtract } from './operations.js'; // Importing multiple functions
console.log(add(5, 3)); // Output: 8
console.log(subtract(10, 4)); // Output: 6
In operation.js:
// operations.ts
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
In HTML:
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ES6 Modules</title>
<script type="module" src="main.js"></script>
</head>
<body>
<!-- Content -->
</body>
</html>
In mathOperations.js:
// mathOperations.ts
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
In main.js:
// main.ts
import * as math from './mathOperations.js'; // Importing all functions as a namespace
console.log(math.add(5, 3)); // Output: 8
console.log(math.subtract(10, 4)); // Output: 6
callback hell! promises is not a substitute of callbacks, but a way to handle them
time dependant container it'a broker from sync and async codeù
can use observer pattern to subscribe to a promise, to be notified when the promise is resolved or rejected
const prom = new Promise((resolve, reject) => { // callback immediately called
setTimeout(() => resolve(5), 3000); // resolve is a function, 5 is the value to return
reject('error') // reject is a function, 'error' is the value to return
});
prom.then(
() => new Promise((resolve, reject) => {
setTimeout(() => resolve(50), 3000); // at the end invoke a callback
})
).then(
data => console.log(data)
).catch(
err => console.log(err)
);
Example of fetch:
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => response.json()) // analyze in json
.then(json => console.log(json))
.catch(err => console.log(err))
Example of post:
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
body: JSON.stringify({
title: 'foo',
body: 'bar',
userId: 1
}),
headers: {
'Content-type': 'application/json; charset=UTF-8'
}
})
async function getData() {
const response = await fetch('https://jsonplaceholder.typicode.com/todos/1'); // await can be used only inside async function
const json = await response.json(); // analyze in json, return a promise, can use await to stop the execution until the promise is resolved
console.log(json);
return json;
}
getData()
.then((json) => console.log(json))
.catch(err => console.log(err))
Typescript extend javascript language, is possible to type variables, functions, classes, interfaces, etc.
Useful for big projects, to avoid errors, to have a better IDE support, to have a better code readability. Typescript help to have better code documentation and faster and more precise code refactoring.
repo to use: git clone https:github.com/fabiobiondi/javascript-playground
let a: number = 1;
a = "b"; // error
The playground can be installed locally through the Github repository clone:
git clone https://github.com/fabiobiondi/typescript-playground
npm install
npm start
If you prefer to disable TypeScript and use plain JavaScript ES6, you can switch branches:
git checkout javascript-playground
D:\00_projects\22_coding\fabioBiondi\es6TypeScript\typescript-playground\
The project works correctly with Node version 16.x and does not work with higher versions. In this case, you can start it with the command npm start.
If you are using Node 18 or higher, you can use the command npm run start:node18 instead.
Since this update was made in June 2023, if you have already downloaded the project before, you will need to download the updates (git pull) or clone the project again (git clone [URL]).
Alternatively, you can create a playground project using Vite.
You can find a guide for its configuration directly on my website. Specifically, by following the first chapters of this tutorial, you can create a Vite project with TypeScript support. However, if you also want type checking (which is not supported by Vite in development but only in production), I recommend following the second chapter of the guide where I explain how to configure it.
The other chapters are not necessary as they concern test configuration.
Inference is the ability of typescript to infer the type of a variable, without specify it.
let a = 1 // inference is number
a = "ciao" //error, inference is for the first assignment, must be number
list of primitive types:
let a: number = 1;
let b: string = "ciao";
let c: boolean = true;
let d: null = null;
let e: undefined = undefined;
let f: symbol = Symbol("ciao");
let g: bigint = 100n;
let h: any = 1; // any type, can be changed. Bad practice
in tsconfig.json:
compilerOptions: {
"noImplicitAny": true, // if true, any type is not allowed: we are forced to decide the type, default is false
}
let user = {id: 1, name: "Fabio"}; // type is any
// normally in user.ts we define the interfaces, we can also use Class or Type
interface User {
id: number;
name: string;
age?: number; // optional property
}
let user2: User = { // type is User
id: 1,
name: "Fabio"
};
console.log(user.surname); // error, surname is not a property of user
interface User{
id: number
name: string
coords: Coords
address?: Address // optional property
}
// user of support type interface, code is more expressive and extensible in big projects or complex objects for server response
interface Coords{
lat: number
lng: number
}
interface Address{
street: string
city: string
homeNumber?: number
zip: number
}
const user: User = {
id: 1,
name: "Fabio",
coords: {
lat: 1,
lng: 2
}
}
console.log(user)
interface User{
id: number
name: string
coords: Coords
address?: Address // optional property
}
const a: User = {
id: 1,
name: "Fabio",
coords: {
lat: 1,
lng: 2
}
}
const b = {
id: 2,
name: "Mario",
coords: {
lat: 1,
lng: 2
}
}
const list : User[] = [
a,b,c,// c is error
{ // this is valid
id: 2,
name: "Mario",
coords: {
lat: 1,
lng: 2
}
}
]
console.log(list[0].name)
use of Generics in typescript:
const list2: Array<User> = [a,b,c]
list2.push({ // this is valid
id: 2,
name: "Mario",
coords: {
lat: 1,
lng: 2
}
})
list2.pop() // remove last element
const list 3 = list2.map(user => user.name) // return a list of names
Interface is 0byte code, is only for typescript, is not compiled in js, no space in memory
Class use OOP paradigm, is compiled in js, is a space in memory
class User{
// id: number
// name: string
constructor(private id: number, private name: string){} // parameters is also type, is not necessary to declare the propertiesù
// if used private or public is automatic created and assigned as a property of the class
// this.id = id
// this.name = name
// this.id = id
// this.name = name
}
const user1: User = new User(1, 'Marco')
const user2: User = new User(2, 'Fabio')
console.log(user1 instanceof User) // true
Type useful to combine more interface or class
type User = { // is the same,
id: number
name: string
}
class User{
constructor(public id: number, private name: string){}
printName(){
console.log(this.name)
}
}
const user1: User = new User(1, 'Marco')
const user2: User = new User(2, 'Fabio')
console.log(user1 instanceof User) // true
user2.name // error
user2.printName() // Marco
class User{
constructor(public id: number, private name: string){}
printName(){
console.log(this.name)
}
get getName(){ // must have return
return this.name
}
set setName(name: string){
this.name = name
}
}
const user1: User = new User(1, 'Marco')
user1.setName = 'Fabio' // setter and getter not parameter but as a value
console.log(user1.getName) // Fabio
function multiply(a: number, b: number): number{
return a * b
}
const result = multiply(2,3) // 6
function hello(): void{ // void is not a type, is a return type
console.log('hello')
}
Method are always functions, but functions are not always methods. Methods are inside a class, functions are not.
type Role = 'admin | guest' // union type
const r: Role = 'root' // error