Generic Types

Introduction aux generics

Les types génériques en essayant de les expliquer simplement, sont des variables de types permettant de passer des types en paramètre d'autres types au même titre qu'on passerait des variables en paramètre d'une fonction.

Generics are a fundamental feature of statically-typed languages, allowing developers to pass types as parameters to another type, function, or other structure. When a developer makes their component a generic component, they give that component the ability to accept and enforce typing that is passed in when the component is used, which improves code flexibility, makes components reusable, and removes duplication. (Cardoso, 2021)

source : Jonathan, C. (2021). How To Use Generics in TypeScript. DigitalOcean.

Syntaxe des generics

Les generics sont déclarés entre chevrons comme ceci : <ArgType>

Ici ArgType représente le type passé en argument.

Par convention on les écrit d'une seule lettre et en majuscule, plutôt comme ceci : <T>

Quand il y a en a plusieurs, on les sépare par une virgule : <X, Y, Z>

Cas d'usages et exemples

Nous allons appréhender cette notion avec des exemples concrets qui seront plus parlant.

Fonctions

Considérons la fonction demo suivante :

function demo(arg: any): any {
    return arg;
}

const res = demo(100);

Elle prend un argument arg de type any et retourne une donnée de type any.

Ce qui veut dire que dans l'exemple, res aura le type any alors qu'on vient de passer un type number à la fonction (100 est un nombre).

Nous venons de perdre le type de l'argument passé dans la fonction ce qui peut être problématique dans de nombreux cas.

Récupérons le type en utilisant les generics

function demo<T>(arg: T): T {
    return arg;
}

const res = demo<number>(100);

On a bien récupéré le bon type :

Voici un exemple d'usage des generics dans une fonction faisant un appel API :

type KrakenApiTickerRes = {
    error: any[],
    result: {
        [pair: string]: {
            a: string[], b: string[], c: string[], v: string[],
            p: string[], t: number[], l: string[], h: string[],
            o: number
        }
    }
}

async function krakenCallAPI<T>(endpoint: string, pair: string): Promise<T> {
    const res = await fetch(`https://api.kraken.com/0/${endpoint}?pair=${pair}`);
    return res.json();
}

// https://api.kraken.com/0/public/Ticker?pair=XXBTZUSD
const res = await krakenCallAPI<KrakenApiTickerRes>('public/Ticker/', 'XXBTZUSD')
const btc_usd_open_price = res.result['XXBTZUSD'].o;

// le call ne fonctionnera pas si vous testez le fichier js dans le navigateur 
// à cause de la CORS policy, mais c'est pour l'exemple

export {}

Dans l'exemple ci-dessus nous avons créé un type KrakenApiTickerRes qui décrit le retour d'un endpoint API de Kraken.

Nous passons ce type dans la fonction krakenCallAPI et magique : notre res prend le type KrakenApiTickerRes au lieu de any !