Union & Intersection Types

L'union de types

Nous avons vu comment spécifier un type particulier à une donnée (variable, arguments de fonctions, etc.)

Mais il y a des cas où nous pourrions avoir besoin d'accepter plusieurs types, c'est là que l'union de types intervient (Union Types in english :p) !

Syntaxe

Pour déclarer une union de types, vous devez lister les types séparés par le caractère pipe | (avec ou sans parenthèses).

ex : number | string | any

ex2 : (number | string | any)

Ex (arguments d'une fonction) :

function showAge(age: number | string) {
    if(typeof age === "string") {
        console.log(`your age is ${parseInt(age, 10)}`);
    } else {
        console.log(`your age is ${age}`);
    }
}

showAge(10);
showAge("10");

Ex (type de retour d'une fonction) :

function getAge(user: {firstName: string, age: string | number}): string | number {
    return user.age;
}

getAge({firstName: "Satoshi", age: 999});
getAge({firstName: "Satoshi", age: "999"});

Ex (avec un alias de type) :

type MetamaskWallet = {
    address: string
    selectedNetwork: 'ethereum' | 'polygon' | 'sepolia' | 'goerli'
}

// ok
const myWallet: MetamaskWallet = { address: '0x1234', selectedNetwork: 'ethereum'}

// pas ok
const myWallet2: MetamaskWallet = { address: '0x1234', selectedNetwork: 'ropsten'}
src/demo.ts:7:56 - error TS2322: Type '"ropsten"' is not assignable to type '"ethereum" | "polygon" | "sepolia" | "goerli"'.

7 const myWallet2: MetamaskWallet = { address: '0x1234', selectedNetwork: 'ropsten'};

Ex (on peut également ajouter des types à une union) :

type City = {
    name: string,
    zipCode: number,
    long: number,
    lat: number,
}

type User = {
    firstName: string,
    lastName: string,
    location: 'unknown' | City | 'metaverse'
}

L'intersection de types

Avec TypeScript il est aussi possible de créer une intersection de type : cela permet de combiner plusieurs types en un seul type !

Pour cela on utilise le symbole esperluette ("ampersand" ou "and sign" en anglais) : &

Attention à la confusion

Je trouve personnellement que c'est très mal nommé car ça porte à confusion avec la théorie des ensembles...

\large A \cap \large B

A "inter" B est censé représenter tous les éléments appartenant à la fois à A et à B.

Mais avec TypeScript c'est différent, prenons l'exemple suivant :

type A = {
    x: number, y: number
}

type B = {
    x: number, y: number, z: number,
}

type C = A & B

// ok
const exampleOk: C = {
    x: 15, y: 10, z: 30
}

// error
const exampleNotOk: C = {
    x: 10, y: 10
}

Le type C qui est l'intersection de A et B s'attend à avoir les propriétés x, y et z :

src/demo.ts:18:7 - error TS2322: Type '{ x: number; y: number; }' is not assignable to type 'C'.
  Property 'z' is missing in type '{ x: number; y: number; }' but required in type 'B'.         
                                                                                                
18 const exampleNotOk: C = {

Il faut donc juste faire attention à ne pas confondre avec l'intersection dans la théorie des ensembles si vous êtes matheux dans l'âme.