Cours 04 - Principes de base de TypeScript

Objectifs

Déroulement

Les types

En plus des types de base de JavaScript, TypeScript permet de créer des types personnalisés (comme des objets) et d'utiliser des unions de types (où une variable peut être de l'un de plusieurs types), rendant le langage très flexible tout en gardant le code sûr et facile à comprendre.

Types en JavaScript :

Types ajoutés en TypeScript :

Liens utiles

Atelier 04 - Utilisation des types

Prérequis

Prenez le temps d'aller lire cette documentation, c'est la doc officielle et complète!

Partie 01 - Les types de base

Pour débuter l'atelier:

Dans le terminal, on installe les dépendances et on lance le serveur:

npm install
npm run dev

On retourne dans index.ts pour faire des tests
À la toute fin du script, ajoutez les lignes suivantes:

let ventes: number = 123456789 // possible d'écrire un nombre large comme suit: 123_456_789
let cours: string = "TypeScript"
let est_publie: boolean = true
let niveau

C'est possible d'enlever la déclaration de type ex:

let est_publie = true //La variable sera typée booléenne à cause du true

Si on passe notre curseur sur la variable niveau on voit son type (any)

On va écrire notre première fonction:

function render(document) {
    console.log(document)
}

Il va y avoir une erreur car le type de document n'est pas spécifié!

Si on ne connais pas le type car c'est un gros projet on va devoir utiliser 'any':

function render(document: any) {
    console.log(document)
}

Donc, any représente tous les types possibles!

Les tableaux en javascript:

let nombres = [1, 2, "3"] // c'est valide!

En TypeScript:

let nombres: number[] = [1, 2, "3"] // c'est pas valide!  
let nombres: number[] = [1, 2, 3] // devient valide! 
let nombres = [1, 2, 3] // fonctionne quand même comme un array de nombre!     

Si on fait un tableau suivant:

let nombres = []   // son type sera any!    
let nombres: number[] = []   // sera mieux et valide ici!      

Maintenant, voici l’autocomplétion en TypeScript, si on écrit:

let nombres: number[] = []
nombres.forEach(n => n.) 

On va voir ici la liste des méthodes qui appartiennent à number!
Vous pouvez effacer cet essai.

Type tuple, exemple:

let usager: [number, string] = [31, "MasterJim"]

Deux valeurs ici mais, on pourrait en mettre plus, mais ma recommandation pour du clean code (pas plus de deux!)

Type enum, exemple:

    // const small = 1
    // const medium = 2
    // cont large = 3

    enum Taille { Small = 1, Medium = 2, Large = 3}
    // ou
    enum Taille { Small = "s", Medium = "m", Large = "l"}
    let maTaille: Taille = Taille.Large

si on utilise

const enum Taille { Small = 1, Medium = 2, Large = 3}

le code JavaScript sera plus optimal!

Les fonctions, exemples:

    function calculerTaxe(montant: number): number {
        return "a"
    }

Ça va donner une erreur, à cause de la valeur de retour number!
Il y a aussi un warning de valeur non utilisée!

function calculerTaxe(montant: number): number {
    return montant * 1.15
}

Ajouter un paramètre optionnel avec un ?

function calculerTaxe(montant: number, annee?: number): number {
    if (annee < 2025)
        return montant * 1.15
    return montant * 1.3
}

calculerTaxe(10_000, 2026, 1) // erreur ici mais pas en javaScript!
calculerTaxe(10_000) // va donner une année undefined en TypeScript

Bonne fonction, avec valeur par défaut à 2024:

function calculerTaxe(montant: number, annee: number = 2024): number {
    if (annee < 2025)
        return montant * 1.15
    return montant * 1.3
}

Les objets:

let employe:{
    id: number,
    nom: string
} = { id: 1,  nom:"Jimmy Gilbert"}

Pour bloquer la modification d'une valeur, exemple l'id:

let employe:{
    readonly id: number,
    nom: string
} = { id: 1,  nom:"Jimmy Gilbert"}

on pourra pas faire par la suite:

employe.id = 23 //donne une erreur

Si on veut ajouter la date de retraite sous forme de méthode:

let employe:{
    readonly id: number,
    nom: string,
    retraite: (date: Date) => void
} = { id: 1,  nom:"Jimmy Gilbert"}

retraite: (date: Date) => void

Pour l'ajouter:

let employe:{
    readonly id: number,
    nom: string,
    retraite: (date: Date) => void
} = { 
    id: 1,  
    nom:"Jimmy Gilbert",
    retraite: (date: Date) => {
        console.log(date)
    }
}

Partie 02 - Typage avancé

De retour à la fin de index.ts, on va faire d'autres tests

Alias de type
Si on reprend l'objet précédemment créé:

let employe: {
    readonly id: number,
    nom: string,
    retraite: (date: Date) => void
} = {
    id: 1,
    nom: "Jimmy Gilbert",
    retraite: (date: Date) => {
        console.log(date)
    }
}

Si on veut refaire un employé on doit refaire tout le code! DRY
Le code est aussi dur à lire...

On va créer un alias de type:

type Employe = {
    readonly id: number,
    nom: string,
    retraite: (date: Date) => void
}

let employe: Employe = {
    id: 1,
    nom: "Jimmy Gilbert",
    retraite: (date: Date) => {
        console.log(date)
    }
}

Le code est pas mal plus facile à lire et ajouter un employé est facile!!

Les unions de types permettent de donner deux types alternatifs à un paramètre dans une fonction

function kgToLbs(poids: number | string): number {
    if (typeof poids === "number"){
        return poids * 2.2
    }else {
        return parseInt(poids) * 2.2 //peut importe la veleur en string tant que le nombre est là!
    }
}

console.log(kgToLbs(90))
console.log(kgToLbs("90kg"))

Les intersections de types permettent de donner deux types en même temps à un paramètre dans une fonction
Exemple pour un élément qui pourrait être déplacé à l'écran:

type Draggable = {
    drag: () => void
}

type Resizable = {
    resize: () => void
}

type UIWidget  = Draggable & Resizable

let zoneTexte: UIWidget = {
    drag: () => {},
    resize: () => {}
}

Les types litéraux, exemple:

let quantite: number // peut être n'importe quel nombre

//Pour limiter les valeurs:
let quantite: 50 | 100 = 50 // 50 ou 100

//On peut utiliser des types!
type Quantite = 50 | 100
let quantite: Quantite = 100

//peut aussi être un string!
type Metrique = 'cm' | 'p'

Les types "null", permet d'utiliser des valeur de type null, mais on doit y penser avec des unions:

function message(nom: string | null){
    if (nom) {
        console.log("ALLO "+nom.toUpperCase+"!") // + pour concater en JS
    } else {
        console.log("ALLO!")
    }
}

message(null) // | null permet d'envoyer une valeur nulle
message("Jimmy") // ça va être un string ici

Chaînage optionnel:

type Client = {
    anniversaire: Date
}

function getClient(id: number): Client | null {
    return id === 0 ? null : { anniversaire: new Date() }
}

let client = getClient(0)
console.log(client?.anniversaire) //va être éxécuté SEULEMENT si le client est défini et pas null
// va retourner undefined

let client = getClient(1)
console.log(client?.anniversaire) //va être éxécuté SEULEMENT si le client est défini et pas null
// va retourner la date

Aller plus loin encore!

type Client = {
    anniversaire?: Date
}

function getClient(id: number): Client | null {
    return id === 0 ? null : { anniversaire: new Date() }
}

let client = getClient(1)
console.log(client?.anniversaire?.fullYear()) //va être éxécuté SEULEMENT si le client est défini et pas null
// va retourner l'année seulement si la valeur est définie

Remise

Aucune remise pour cet atelier