IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

TypeScript 4.9 Beta est disponible et apporte la restriction des propriétés non listées avec l'opérateur in,
Ainsi que la vérification de l'égalité sur NaN

Le , par Bruno

126PARTAGES

3  0 
TypeScript, c'est un langage qui s'appuie sur JavaScript et ajoute une syntaxe pour les types. Dans un article publié sur son blog ce 23 septembre, Microsoft a annoncé la version bêta de TypeScript 4.9.

Les types aident à décrire les types de valeurs avec lesquelles vous travaillez et les types de fonctions que vous appelez. TypeScript peut utiliser ces informations pour vous aider à éviter les erreurs telles que les fautes de frappe, les arguments manquants ou l'oubli de vérifier null et undefined ! Mais cette vérification de type n'est pas la seule chose que fait TypeScript - il utilise les informations de ces types pour vous offrir une expérience d'édition, alimentant des éléments tels que la complétion de code, la définition, le changement de nom, etc.


Voici, ci-dessous, les nouveautés qu’apporte TypeScript 4.9 :

L'opérateur satisfies

Les développeurs TypeScript sont souvent confrontés à un dilemme : nous voulons nous assurer qu'une expression correspond à un certain type, mais nous voulons également conserver le type le plus spécifique de cette expression à des fins d'inférence. Par exemple :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
// Each property can be a string or an RGB tuple.
const palette = {
    red: [255, 0, 0],
    green: "#00ff00",
    bleu: [0, 0, 255]
//  ^^^^ sacré bleu - we've made a typo!
};

// We want to be able to use array methods on 'red'...
const redComponent = palette.red.at(0);

// or string methods on 'green'...
const greenNormalized = palette.green.toUpperCase();

Remarquez qu'il est écrit bleu, alors qu'on aurait probablement dû écrire blue. La faute de frappe de bleu peut être corrigée en utilisant une annotation de type sur palette, mais des informations seraient perdues sur chaque propriété.

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
type Colors = "red" | "green" | "blue";

type RGB = [red: number, green: number, blue: number];

const palette: Record<Colors, string | RGB> = {
    red: [255, 0, 0],
    green: "#00ff00",
    bleu: [0, 0, 255]
//  ~~~~ The typo is now correctly detected
};

// But we now have an undesirable error here - 'palette.red' "could" be a string.
const redComponent = palette.red.at(0);

Le nouvel opérateur satisfies permet de valider que le type d'une expression correspond à un certain type, sans modifier le type résultant de cette expression. Par exemple, nous pourrions utiliser satisfies pour valider que toutes les propriétés de palette sont compatibles avec string | number[] :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
type Colors = "red" | "green" | "blue";

type RGB = [red: number, green: number, blue: number];

const palette = {
    red: [255, 0, 0],
    green: "#00ff00",
    bleu: [0, 0, 255]
//  ~~~~ The typo is now caught!
} satisfies Record<Colors, string | RGB>;

// Both of these methods are still accessible!
const redComponent = palette.red.at(0);
const greenNormalized = palette.green.toUpperCase();

satisfies peut être utilisé pour détecter de nombreuses erreurs possibles. Par exemple, nous pouvons nous assurer qu'un objet possède toutes les clés d'un certain type, mais pas plus :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
type Colors = "red" | "green" | "blue";

// Ensure that we have exactly the keys from 'Colors'.
const favoriteColors = {
    "red": "yes",
    "green": false,
    "blue": "kinda",
    "platypus": false
//  ~~~~~~~~~~ error - "platypus" was never listed in 'Colors'.
} satisfies Record<Colors, unknown>;

// All the information about the 'red', 'green', and 'blue' properties are retained.
const g: boolean = favoriteColors.green;

Peut-être que nous ne nous soucions pas de savoir si les noms des propriétés correspondent d'une manière ou d'une autre, mais que nous nous soucions des types de chaque propriété. Dans ce cas, nous pouvons également nous assurer que toutes les valeurs des propriétés d'un objet sont conformes à un certain type.

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
type RGB = [red: number, green: number, blue: number];

const palette = {
    red: [255, 0, 0],
    green: "#00ff00",
    blue: [0, 0]
    //    ~~~~~~ error!
} satisfies Record<string, string | RGB>;

// Information about each property is still maintained.
const redComponent = palette.red.at(0);
const greenNormalized = palette.green.toUpperCase();

Restriction des propriétés non listées avec l'opérateur in

En tant que développeurs, nous devons souvent traiter des valeurs qui ne sont pas entièrement connues au moment de l'exécution. En fait, il arrive souvent que nous ne sachions pas si des propriétés existent, que nous obtenions une réponse d'un serveur ou que nous lisions un fichier de configuration. L'opérateur in de JavaScript peut vérifier si une propriété existe sur un objet. Auparavant, TypeScript nous permettait d'éliminer tous les types qui ne listaient pas explicitement une propriété.

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
interface RGB {
    red: number;
    green: number;
    blue: number;
}

interface HSV {
    hue: number;
    saturation: number;
    value: number;
}

function setColor(color: RGB | HSV) {
    if ("hue" in color) {
        // 'color' now has the type HSV
    }
    // ...
}

Ici, le type RGB n'a pas listé la teinte et a été restreint, nous laissant avec le type HSV. Mais qu'en est-il des exemples où aucun type ne mentionne une propriété donnée ? Dans ces cas-là, le langage ne nous a pas beaucoup aidés. Prenons l'exemple suivant en JavaScript :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
function tryGetPackageName(context) {
    const packageJSON = context.packageJSON;
    // Check to see if we have an object.
    if (packageJSON && typeof packageJSON === "object") {
        // Check to see if it has a string name property.
        if ("name" in packageJSON && typeof packageJSON.name === "string") {
            return packageJSON.name;
        }
    }

    return undefined;
}

La réécriture en TypeScript canonique serait juste une question de définition et d'utilisation d'un type pour le contexte ; cependant, le choix d'un type fiable comme unknown pour la propriété packageJSON causerait des problèmes dans les anciennes versions de TypeScript.

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
interface Context {
    packageJSON: unknown;
}

function tryGetPackageName(context: Context) {
    const packageJSON = context.packageJSON;
    // Check to see if we have an object.
    if (packageJSON && typeof packageJSON === "object") {
        // Check to see if it has a string name property.
        if ("name" in packageJSON && typeof packageJSON.name === "string") {
        //                                              ~~~~
        // error! Property 'name' does not exist on type 'object.
            return packageJSON.name;
        //                     ~~~~
        // error! Property 'name' does not exist on type 'object.
        }
    }

    return undefined;
}

En effet, alors que le type de packageJSON est passé d'inconnu à objet, l'opérateur in est strictement limité aux types qui définissent réellement la propriété vérifiée. Par conséquent, le type de packageJSON est resté objet. TypeScript 4.9 rend l'opérateur in un peu plus puissant lorsqu'il s'agit de restreindre les types qui ne répertorient pas du tout la propriété. Au lieu de les laisser tels quels, le langage intersectera leurs types avec Record<"property-key-being-checked", unknown>.

Ainsi, dans notre exemple, le type de packageJSON sera réduit d'inconnu à objet Record<"name", unknown>. Cela nous permet d'accéder directement à packageJSON.name et de le réduire...
La fin de cet article est réservée aux abonnés. Soutenez le Club Developpez.com en prenant un abonnement pour que nous puissions continuer à vous proposer des publications.

Une erreur dans cette actualité ? Signalez-nous-la !