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

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

TypeScript Discussion :

Microsoft annonce la disponibilité de TypeScript 5.8 RC avec plusieurs améliorations


Sujet :

TypeScript

  1. #1
    Chroniqueur Actualités
    Avatar de Anthony
    Homme Profil pro
    Rédacteur technique
    Inscrit en
    Novembre 2022
    Messages
    1 476
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Rédacteur technique

    Informations forums :
    Inscription : Novembre 2022
    Messages : 1 476
    Par défaut Microsoft annonce la disponibilité de TypeScript 5.8 RC avec plusieurs améliorations
    Microsoft annonce la disponibilité de TypeScript 5.8 Beta avec plusieurs améliorations, dont une meilleure vérification des types de retours pour les types d'accès conditionnels et indexés

    Microsoft vient de publier la version bêta de TypeScript 5.8. Cette version améliore la façon dont les types de retour sont vérifiés pour les types d'accès conditionnels et indexés, optimise l'interopérabilité des modules dans Node.js, et inclut des améliorations de performance pour une résolution plus rapide des projets.

    Pour commencer à utiliser la version bêta, vous pouvez l'obtenir via npm avec la commande suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    npm install -D typescript@beta


    Nom : typescript 5.8 beta.png
Affichages : 8944
Taille : 28,3 Ko

    Retours vérifiés pour les types d'accès conditionnels et indexés

    Considérons une API qui présente un ensemble d'options à un utilisateur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    /**
     * @param prompt The text to show to a user.
     * @param selectionKind Whether a user can select multiple options, or just a single option.
     * @param items Each of the options presented to the user.
     **/
    async function showQuickPick(
        prompt: string,
        selectionKind: SelectionKind,
        items: readonly string[],
    ): Promise<string | string[]> {
        // ...
    }
     
    enum SelectionKind {
        Single,
        Multiple,
    }

    L'objectif de showQuickPick est d'afficher un élément d'interface utilisateur qui permet de sélectionner une ou plusieurs options. Le moment où il le fait est déterminé par le paramètre selectionKind. Lorsque selectionKind est SelectionKind.Single, le type de retour de showQuickPick doit être string, et lorsqu'il est SelectionKind.Multiple, le type de retour doit être string[].

    Le problème est que la signature de type de showQuickPick n'est pas claire. Elle indique simplement que le type retourné est string | string[] - il pourrait s'agir d'un string ou d'une string[], mais l'appelant doit vérifier explicitement. Dans l'exemple ci-dessous, on pourrait s'attendre à ce que shoppingList ait le type string[], mais on se retrouve avec le type plus large string | string[].

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    let shoppingList = await showQuickPick(
        "Which fruits do you want to purchase?",
        SelectionKind.Multiple,
        ["apples", "oranges", "bananas", "durian"],
    );
     
    console.log(`Alright, going out to buy some ${shoppingList.join(", ")}`);
    //                                                         ~~~~
    // error!
    // Property 'join' does not exist on type 'string | string[]'.
    //  Property 'join' does not exist on type 'string'.

    Au lieu de cela, nous pouvons utiliser un type conditionnel pour rendre le type de retour de showQuickPick plus précis :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    type QuickPickReturn<S extends SelectionKind> =
        S extends SelectionKind.Multiple ? string[] : string
     
    async function showQuickPick<S extends SelectionKind>(
        prompt: string,
        selectionKind: S,
        items: readonly string[],
    ): Promise<QuickPickReturn<S>> {
        // ...
    }

    Cela fonctionne bien pour les appelants.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // `SelectionKind.Multiple` gives a `string[]` - works 
    let shoppingList: string[] = await showQuickPick(
        "Which fruits do you want to purchase?",
        SelectionKind.Multiple,
        ["apples", "oranges", "bananas", "durian"],
    );
     
    // `SelectionKind.Single` gives a `string` - works 
    let dinner: string = await showQuickPick(
        "What's for dinner tonight?",
        SelectionKind.Single,
        ["sushi", "pasta", "tacos", "ugh I'm too hungry to think, whatever you want"],
    );

    Mais qu'en est-il si nous essayons d'implémenter showQuickPick ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    async function showQuickPick<S extends SelectionKind>(
        prompt: string,
        selectionKind: S,
        items: readonly string[],
    ): Promise<QuickPickReturn<S>> {
        if (items.length < 1) {
            throw new Error("At least one item must be provided.");
        }
     
        // Create buttons for every option.
        let buttons = items.map(item => ({
            selected: false,
            text: item,
        }));
     
        // Default to the first element if necessary.
        if (selectionKind === SelectionKind.Single) {
            buttons[0].selected = true;
        }
     
        // Event handling code goes here...
     
        // Figure out the selected items
        const selectedItems = buttons
            .filter(button => button.selected)
            .map(button => button.text);
     
        if (selectionKind === SelectionKind.Single) {
            // Pick the first (only) selected item.
            return selectedItems[0];
        }
        else {
            // Return all selected items.
            return selectedItems;
        }
    }

    Malheureusement, TypeScript émet une erreur sur chacune des instructions de retour.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Type 'string[]' is not assignable to type 'QuickPickReturn<S>'.
    Type 'string' is not assignable to type 'QuickPickReturn<S>'.

    Jusqu'à présent, TypeScript exigeait une assertion de type pour implémenter toute fonction renvoyant un type conditionnel d'ordre supérieur.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
          if (selectionKind === SelectionKind.Single) {
              // Pick the first (only) selected item.
    -         return selectedItems[0];
    +         return selectedItems[0] as QuickPickReturn<S>;
          }
          else {
              // Return all selected items.
    -         return selectedItems;
    +         return selectedItems as QuickPickReturn<S>;
          }

    Cette situation n'est pas idéale car les assertions de type annulent les vérifications légitimes que TypeScript effectuerait autrement. Par exemple, il serait idéal que TypeScript puisse détecter le bogue suivant où chaque branche du if/else est mélangée :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
        if (selectionKind === SelectionKind.Single) {
            // Oops! Returning an array when the caller expects a single item!
            return selectedItems;
        }
        else {
            // Oops! Returning a single item when the caller expects an array! 
            return selectedItems[0];
        }

    Pour éviter les assertions de type, TypeScript 5.8 prend désormais en charge une forme limitée de vérification des types conditionnels dans les instructions de retour. Lorsque le type de retour d'une fonction est un type conditionnel générique, TypeScript utilise désormais l'analyse du flux de contrôle pour les paramètres génériques dont les types sont utilisés dans le type conditionnel, instancie le type conditionnel avec le type réduit de chaque paramètre, et effectue une vérification par rapport à ce nouveau type.

    Qu'est-ce que cela signifie en pratique ? Tout d'abord, examinons quels genres de types conditionnels impliquent une réduction. Pour refléter la façon dont la réduction opère dans les expressions, nous devons être plus explicites et exhaustifs sur ce qui se passe dans chaque branche.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    type QuickPickReturn<S extends SelectionKind> =
        S extends SelectionKind.Multiple ? string[] :
        S extends SelectionKind.Single ? string :
        never;

    Une fois que c'est fait, tout fonctionne dans l'exemple que nous venons de donner. Les appelants n'ont aucun problème, et l'implémentation est maintenant sûre. Et si l'on essaie d'intervertir le contenu des branches du if, TypeScript le signale correctement comme une erreur.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
        if (selectionKind === SelectionKind.Single) {
            // Oops! Returning an array when the caller expects a single item!
            return selectedItems;
        //  ~~~~~~
        // error! Type 'string[]' is not assignable to type 'string'.
        }
        else {
            // Oops! Returning a single item when the caller expects an array! 
            return selectedItems[0];
        //  ~~~~~~
        // error! Type 'string[]' is not assignable to type 'string'.
    }

    Notez que TypeScript fait désormais quelque chose de similaire si l'on utilise des types d'accès indexés. Au lieu d'un type conditionnel, il est possible d'utiliser un type qui agit comme un plan de SelectionKind vers le type de retour que l'on souhaite :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    interface QuickPickReturn {
        [SelectionKind.Single]: string;
        [SelectionKind.Multiple]: string[];
    }
     
    async function showQuickPick<S extends SelectionKind>(
        prompt: string,
        selectionKind: S,
        items: readonly string[],
    ): Promise<QuickPickReturn[S]> {
        // ...
    }

    Pour de nombreux utilisateurs, il s'agira d'une manière plus ergonomique d'écrire le même code. Toutefois, cette fonctionnalité présente certaines limitations.

    Prise en charge de require() pour les modules ECMAScript dans --module nodenext

    Pendant des années, Node.js a supporté les modules ECMAScript (ESM) en même temps que les modules CommonJS. Malheureusement, l'interopérabilité entre les deux a posé quelques problèmes.

    • Les fichiers ESM pouvaient utiliser import sur des fichiers CommonJS
    • Les fichiers CommonJS ne pouvaient pas utiliser require() pour les fichiers ESM

    En d'autres termes, il était possible de consommer des fichiers CommonJS à partir de fichiers ESM, mais pas l'inverse. Cela a posé de nombreux problèmes aux auteurs de bibliothèques qui souhaitaient fournir un support ESM. Ces auteurs devaient soit rompre la compatibilité avec les utilisateurs de CommonJS, soit « publier deux fois » leurs bibliothèques (en fournissant des points d'entrée distincts pour ESM et CommonJS), soit rester indéfiniment sur CommonJS. Bien que la double publication puisse sembler être un bon compromis, il s'agit d'un processus complexe et sujet aux erreurs, qui double également la quantité de code dans un paquetage.

    Node.js 22 assouplit certaines de ces restrictions et autorise les appels require("esm") des modules CommonJS vers les modules ECMAScript. Node.js n'autorise toujours pas l'utilisation de require() pour les fichiers ESM qui contiennent un await de premier niveau, mais la plupart des autres fichiers ESM peuvent désormais être consommés à partir de fichiers CommonJS. Cela représente une opportunité majeure pour les auteurs de bibliothèques de fournir un support ESM sans avoir à publier leurs bibliothèques en double.

    TypeScript 5.8 supporte ce comportement avec l'option --module nodenext. Lorsque --module nodenext est activé, TypeScript évitera d'émettre des erreurs sur ces appels require() aux fichiers ESM.

    Parce que cette fonctionnalité peut être rétroportée vers des versions plus anciennes de Node.js, il n'y a actuellement pas d'option stable --module nodeXXXX qui permette ce comportement ; cependant, il est prévu que les futures versions de TypeScript puissent stabiliser cette fonctionnalité sous node20. En attendant, les utilisateurs de Node.js 22 et plus récents sont encouragés à utiliser --module nodenext, tandis que les auteurs de bibliothèques et les utilisateurs de versions plus anciennes de Node.js devraient continuer à utiliser --module node16 (ou faire la mise à jour mineure vers --module node18).

    --module node18

    TypeScript 5.8 introduit un flag stable --module node18. Pour les utilisateurs qui sont fixés sur l'utilisation de Node.js 18, ce drapeau fournit un point de référence stable qui n'incorpore pas certains comportements qui sont dans --module nodenext. En particulier :

    • require() des modules ECMAScript est interdit sous node18, mais autorisé sous nodenext
    • les assertions import (dépréciées en faveur des attributs import) sont autorisées sous node18, mais ne sont pas autorisées sous nodenext

    L'option --erasableSyntaxOnly

    Récemment, Node.js 23.6 a supprimé le support expérimental pour l'exécution directe de fichiers TypeScript ; cependant, seules certaines constructions sont supportées dans ce mode. Node.js a supprimé un mode appelé --experimental-strip-types qui exige que toute syntaxe spécifique à TypeScript ne puisse pas avoir de sémantique d'exécution. En d'autres termes, il doit être possible d'effacer facilement toute syntaxe spécifique à TypeScript d'un fichier, en laissant un fichier JavaScript valide.

    Cela signifie que des constructions comme celles qui suivent ne sont pas prises en charge :

    • déclarations enum
    • namespaces et modules avec code runtime
    • propriétés des paramètres dans les classes
    • alias import

    Des outils similaires comme ts-blank-space ou Amaro (la bibliothèque sous-jacente pour la séparation des types dans Node.js) ont les mêmes limitations. Ces outils fourniront des messages d'erreur utiles s'ils rencontrent du code qui ne répond pas à ces exigences, mais vous ne découvrirez toujours pas que votre code ne fonctionne pas tant que vous n'aurez pas essayé de l'exécuter.

    C'est pourquoi TypeScript 5.8 introduit l'option --erasableSyntaxOnly. Lorsque ce drapeau est activé, TypeScript ne vous permet d'utiliser que des constructions qui peuvent être effacées d'un fichier, et émet une erreur s'il rencontre des constructions qui ne peuvent pas être effacées.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class C {
        constructor(public x: number) { }
        //          ~~~~~~~~~~~~~~~~
        // error! This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
        }
    }

    Le flag --libReplacement

    Dans TypeScript 4.5, la possibilité de remplacer les fichiers lib par défaut par des fichiers personnalisés a été introduite. Ceci était basé sur la possibilité de résoudre un fichier de bibliothèque à partir de paquets nommés @typescript/lib-*. Par exemple, vous pouvez verrouiller vos bibliothèques dom sur une version spécifique du package @types/web avec le package.json suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    {
        "devDependencies": {
           "@typescript/lib-dom": "npm:@types/web@0.0.199"
         }
    }

    Une fois installé, un paquetage appelé @typescript/lib-dom devrait exister, et TypeScript le recherchera toujours lorsque dom est impliqué par vos paramètres.

    Il s'agit d'une fonctionnalité puissante, mais qui implique également un peu de travail supplémentaire. Même si vous n'utilisez pas cette fonctionnalité, TypeScript effectue toujours cette recherche et doit surveiller les changements dans node_modules au cas où un paquetage de remplacement lib commencerait à exister.

    TypeScript 5.8 introduit l'option --libReplacement, qui permet de désactiver ce comportement. Si vous n'utilisez pas --libReplacement, vous pouvez maintenant le désactiver avec --libReplacement false. Dans le futur, --libReplacement false pourrait devenir la valeur par défaut, donc si vous utilisez actuellement ce comportement, vous devriez envisager de l'activer explicitement avec --libReplacement true.

    Conservation des noms de propriété calculés dans les fichiers de déclaration

    Afin de rendre l'émission des propriétés calculées plus prévisible dans les fichiers de déclaration, TypeScript 5.8 préservera systématiquement les noms d'entités (bareVariables et dotted.names.that.look.like.this) dans les noms de propriétés calculées dans les classes.

    Par exemple, considérons le code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    export let propName = "theAnswer";
     
    export class MyClass {
        [propName] = 42;
    //  ~~~~~~~~~~
    // error!
    // A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type.
    }

    Les versions précédentes de TypeScript émettaient une erreur lors de la génération d'un fichier de déclaration pour ce module, et un fichier de déclaration au mieux de sa forme générait une signature d'index.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    export declare let propName: string;
    export declare class MyClass {
        [x: string]: number;
    }

    Dans TypeScript 5.8, l'exemple de code est désormais autorisé et le fichier de déclaration généré correspondra à ce que vous avez écrit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    export declare let propName: string;
    export declare class MyClass {
        [propName]: number;
    }

    Notez que cela ne crée pas de propriétés nommées statiquement sur la classe. Vous obtiendrez toujours ce qui est en fait une signature d'index comme [x : string] : number, donc pour ce cas d'utilisation, vous devrez utiliser des unique symbol ou des types littéraux.

    Notez que l'écriture de ce code était et est toujours une erreur sous le flag --isolatedDeclarations ; mais il est prévu que grâce à ce changement, les noms de propriétés calculés seront généralement autorisés dans les déclarations emit.

    Il est possible (bien que peu probable) qu'un fichier compilé en TypeScript 5.8 génère un fichier de déclaration qui n'est pas rétrocompatible avec TypeScript 5.7 ou antérieur.

    Optimisation du chargement et de la mise à jour des programmes

    TypeScript 5.8 introduit un certain nombre d'optimisations qui peuvent à la fois améliorer le temps de construction d'un programme, et également mettre à jour un programme basé sur un changement de fichier, que ce soit en mode --watch ou dans les scénarios de l'éditeur.

    Tout d'abord, TypeScript évite désormais les allocations de tableaux qui seraient nécessaires lors de la normalisation des chemins. Typiquement, la normalisation des chemins implique de segmenter chaque portion d'un chemin en un tableau de chaînes de caractères, de normaliser le chemin résultant sur la base des segments relatifs, puis de les réunir à l'aide d'un séparateur canonique. Pour les projets comportant de nombreux fichiers, cela peut représenter un travail important et répétitif. TypeScript évite désormais d'allouer un tableau et opère plus directement sur les index du chemin d'origine.

    De plus, lorsque des modifications sont apportées sans changer la structure fondamentale d'un projet, TypeScript évite désormais de revalider les options qui lui sont fournies (par exemple, le contenu d'un tsconfig.json). Cela signifie, par exemple, qu'une simple modification peut ne pas nécessiter de vérifier que les chemins de sortie d'un projet n'entrent pas en conflit avec les chemins d'entrée. Au lieu de cela, les résultats de la dernière vérification peuvent être utilisés. Cela devrait permettre aux éditeurs de grands projets d'être plus réactifs.

    Changements de comportement notables

    L'ensemble des changements de comportement notables qu'il convient de reconnaître et de comprendre dans le cadre de la mise à jour sont disponibles ici.

    Quelles sont les prochaines étapes ?

    À ce stade, TypeScript 5.8 est « feature-stable ». TypeScript 5.8 se concentrera sur les corrections de bogues, le polissage et certaines fonctionnalités à faible risque de l'éditeur. Une version candidate sera disponible dans les prochaines semaines, suivie d'une version stable peu après.

    Source : Microsoft

    Et vous ?

    Que pensez-vous des améliorations apportées par cette version de TypeScript 5.8 ? Les trouvez-vous intéressantes et utiles ?

    Voir aussi :

    Microsoft annonce la Release Candidate de TypeScript 5.7 avec plusieurs améliorations, dont la réécriture de chemin pour les chemins relatifs et des contrôles pour les variables non initialisées

    Microsoft annonce la disponibilité de TypeScript 5.7 Beta, apportant des améliorations à la vérification des variables jamais initialisées et une vérification plus rapide de la propriété d'un projet

    Microsoft annonce la disponibilité de TypeScript 5.6, apportant des améliorations à la vérification vraie et nulle non autorisée ainsi que des méthodes d'aide pour les itérateurs
    Contribuez au club : corrections, suggestions, critiques, ... Contactez le service news et Rédigez des actualités

  2. #2
    Chroniqueur Actualités
    Avatar de Anthony
    Homme Profil pro
    Rédacteur technique
    Inscrit en
    Novembre 2022
    Messages
    1 476
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Rédacteur technique

    Informations forums :
    Inscription : Novembre 2022
    Messages : 1 476
    Par défaut Microsoft annonce la disponibilité de TypeScript 5.8 RC
    Microsoft annonce la Release Candidate de TypeScript 5.8, et apporte des vérifications plus granulaires pour les branches dans les expressions de retour

    La Release Candidate (RC) de TypeScript 5.8 est désormais disponible. Cette version apporte des vérifications plus granulaires pour les branches dans les expressions de retour, en plus des mises à jours déjà présentées dans l'annonce de la version bêta.

    La disponibilité de TypeScript 5.8 Beta a été annoncée par Microsoft au début du mois de février 2025. Cette version bêta offre plusieurs améliorations importantes, dont une meilleure vérification des types de retour pour les types d'accès conditionnels et indexés, le support pour require() des modules ECMAScript dans --module nodenext, l'introduction de l'option --erasableSyntaxOnly, l'ajout de l'option --libReplacement ou des optimisations sur le chargement du programme.


    Pour commencer à utiliser la Release Candidate de TypeScript 5.8, vous pouvez l'obtenir via npm avec la commande suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    npm install -D typescript@rc

    Quelles sont les nouveautés depuis la version bêta ?

    Depuis la sortie de la version bêta, Microsoft a dû reprendre une partie du travail sur la façon dont les fonctions avec des types de retour conditionnels sont vérifiées. En se basant sur certaines limitations et modifications que l'équipe de TypeScript souhaitait apporter, elle a décidé d'itérer sur la fonctionnalité avec l'objectif de la livrer dans TypeScript 5.9. Cependant, dans le cadre de ce travail, l'équipe a ajouté des vérifications plus granulaires pour les branches dans les expressions de retour. Cette amélioration n'a pas été documentée dans le billet de la version bêta, mais restera dans TypeScript 5.8.

    Vérifications granulaires des branches dans les expressions de retour

    Considérons un code comme le suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    declare const untypedCache: Map<any, any>;
     
    function getUrlObject(urlString: string): URL {
        return untypedCache.has(urlString) ?
            untypedCache.get(urlString) :
            urlString;
    }

    L'intention de ce code est de récupérer un objet URL à partir d'un cache s'il existe, ou de créer un nouvel objet URL s'il n'existe pas. Cependant, il existe un bogue : on a oublié de construire un nouvel objet URL avec les données d'entrée. Malheureusement, TypeScript ne détecte généralement pas ce genre de bogue.

    Lorsque TypeScript vérifie des expressions conditionnelles telles que cond ? trueBranch : falseBranch, son type est traité comme une union des types des deux branches. En d'autres termes, il obtient le type de trueBranch et de falseBranch, et les combine en un type d'union. Dans ce cas, le type de untypedCache.get(urlString) est any, et le type de urlString est string. C'est là que les choses se gâtent, car le type any est tellement infectieux dans la manière dont il interagit avec les autres types. L'union any | string est simplifiée en any, donc au moment où TypeScript commence à vérifier si l'expression dans l'instruction return est compatible avec le type de retour attendu de URL, le système de type a perdu toute information qui aurait permis de détecter le bogue dans ce code.

    Dans TypeScript 5.8, le système de type traite les expressions conditionnelles directement à l'intérieur des instructions return. Chaque branche de l'expression conditionnelle est vérifiée par rapport au type de retour déclaré de la fonction qui la contient (s'il y en a un), de sorte que le système de type peut détecter le bogue dans l'exemple ci-dessus.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    declare const untypedCache: Map<any, any>;
     
    function getUrlObject(urlString: string): URL {
        return untypedCache.has(urlString) ?
            untypedCache.get(urlString) :
            urlString;
        //  ~~~~~~~~~
        // error! Type 'string' is not assignable to type 'URL'.
    }

    Cette modification a été apportée dans le cadre d'un ensemble plus large d'améliorations futures pour TypeScript.

    Quelle est la suite ?

    À ce stade, Microsoft prévoit très peu de changements pour TypeScript 5.8, hormis des corrections de bogues critiques pour le compilateur et des corrections de bogues mineurs pour le service de langage. Dans les prochaines semaines, la première version stable de TypeScript 5.8 sera publiée. L'équipe de TypeScript recommande ainsi de garder un œil sur le plan d'itération pour connaître les dates de sortie et plus si vous avez besoin de vous coordonner.

    Microsoft conclut :

    Nous nous concentrons sur le développement de la prochaine version de TypeScript, et nous aurons le plan d'itération disponible dans les prochains jours (y compris les dates de sortie prévues). De plus, nous facilitons l'utilisation des nightly builds de TypeScript sur npm, et il existe une extension pour utiliser ces nightly releases dans Visual Studio Code. Alors, essayez la RC ou nos nightlies ! Nous vous encourageons à nous faire part de vos commentaires sur GitHub.
    Source : Microsoft

    Et vous ?

    Quel est votre avis sur le sujet ?
    Quelles sont les fonctionnalités que vous aimeriez retrouver dans les futures versions de TypeScript ?

    Voir aussi :

    Microsoft annonce la disponibilité de TypeScript 5.8 Beta avec plusieurs améliorations, dont une meilleure vérification des types de retours pour les types d'accès conditionnels et indexés

    Microsoft annonce la Release Candidate de TypeScript 5.7 avec plusieurs améliorations, dont la réécriture de chemin pour les chemins relatifs et des contrôles pour les variables non initialisées
    Contribuez au club : corrections, suggestions, critiques, ... Contactez le service news et Rédigez des actualités

  3. #3
    Chroniqueur Actualités
    Avatar de Anthony
    Homme Profil pro
    Rédacteur technique
    Inscrit en
    Novembre 2022
    Messages
    1 476
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Rédacteur technique

    Informations forums :
    Inscription : Novembre 2022
    Messages : 1 476
    Par défaut Microsoft annonce la disponibilité de TypeScript 5.8
    Microsoft annonce la disponibilité de TypeScript 5.8, apportant des vérifications plus granulaires pour les branches dans les expressions de retour, ainsi que plusieurs autres nouveautés et améliorations

    Microsoft annonce la disponibilité générale (GA) de TypeScript 5.8. Cette version apporte plusieurs nouveautés et améliorations, cependant, une nouvelle fonctionnalité introduite lors de la phase bêta, une forme limitée de vérification des types conditionnels dans les instructions de retour, a été supprimée de la version GA.

    Cette annonce intervient après la publication de la release candidate de TypeScript 5.8, qui apporte des contrôles plus granulaires pour les branches à l'intérieur des expressions de retour. Avec ces contrôles granulaires, le système de type traite les expressions conditionnelles directement à l'intérieur des instructions de retour. Chaque branche de l'expression conditionnelle est ainsi vérifiée par rapport au type de retour déclaré de la fonction qui la contient, s'il en existe un.

    TypeScript est un langage qui s'appuie sur JavaScript en ajoutant une syntaxe pour les types. L'écriture de types dans le code permet d'expliquer l'intention et de faire vérifier le code par d'autres outils pour détecter les erreurs comme les fautes de frappe, les problèmes avec null et undefined, et plus encore. Les types alimentent également les outils d'édition de TypeScript, comme l'auto-complétion, la navigation dans le code et les refactorisations que vous pouvez voir dans des éditeurs tels que Visual Studio et VS Code. En fait, TypeScript et son écosystème alimentent l'expérience JavaScript dans ces deux éditeurs également.


    Pour commencer à utiliser TypeScript 5.8, vous pouvez l'installer via npm avec la commande suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    npm install -D typescript

    Jetons un coup d'œil aux nouveautés de TypeScript 5.8.

    Quelles sont les nouveautés depuis la bêta et la RC ?

    Depuis la sortie de la version bêta, Microsoft a dû faire marche arrière sur la façon dont les fonctions avec des types de retour conditionnels sont vérifiées. Sur la base de certaines limitations et modifications que Microsoft souhaitait apporter, l'équipe a décidé d'itérer sur la fonctionnalité dans le but de la livrer dans TypeScript 5.9. Cependant, dans le cadre de ce travail, Microsoft a ajouté des vérifications plus granulaires pour les branches dans les expressions de retour.

    Aucun nouveau changement majeur n'a été ajouté depuis la version candidate.

    Vérifications granulaires des branches dans les expressions de retour

    Considérons un code comme le suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    declare const untypedCache: Map<any, any>;
     
    function getUrlObject(urlString: string): URL {
        return untypedCache.has(urlString) ?
            untypedCache.get(urlString) :
            urlString;
    }

    L'intention de ce code est de récupérer un objet URL à partir d'un cache s'il existe, ou de créer un nouvel objet URL s'il n'existe pas. Cependant, il y a un bug : on a oublié de construire un nouvel objet URL avec l'entrée. Malheureusement, TypeScript ne détecte généralement pas ce genre de bogue.

    Lorsque TypeScript vérifie des expressions conditionnelles comme cond ? trueBranch : falseBranch, son type est traité comme une union des types des deux branches. En d'autres termes, il obtient le type de trueBranch et de falseBranch, et les combine en un type d'union. Dans ce cas, le type de untypedCache.get(urlString) est any, et le type de urlString est string. C'est là que les choses se gâtent, car le type any est tellement infectieux dans la manière dont il interagit avec les autres types. L'union any | string est simplifiée en any, de sorte qu'au moment où TypeScript commence à vérifier si l'expression de l'instruction return est compatible avec le type de retour attendu d'URL, le système de types a perdu toute information qui aurait permis de détecter le bogue dans ce code.

    Dans TypeScript 5.8, le système de type traite les expressions conditionnelles directement à l'intérieur des instructions return. Chaque branche de l'expression conditionnelle est vérifiée par rapport au type de retour déclaré de la fonction qui la contient (s'il y en a un), de sorte que le système de type peut détecter le bogue dans l'exemple ci-dessus.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    declare const untypedCache: Map<any, any>;
     
    function getUrlObject(urlString: string): URL {
        return untypedCache.has(urlString) ?
            untypedCache.get(urlString) :
            urlString;
        //  ~~~~~~~~~
        // error! Type 'string' is not assignable to type 'URL'.
    }

    Prise en charge de require() pour les modules ECMAScript dans --module nodenext

    Pendant des années, Node.js a supporté les modules ECMAScript (ESM) en même temps que les modules CommonJS. Malheureusement, l'interopérabilité entre les deux a posé quelques problèmes.

    • Les fichiers ESM pouvaient import des fichiers CommonJS
    • Les fichiers CommonJS ne pouvaient pas require() les fichiers ESM

    En d'autres termes, il était possible de consommer des fichiers CommonJS à partir de fichiers ESM, mais pas l'inverse. Cela a posé de nombreux problèmes aux auteurs de bibliothèques qui souhaitaient fournir un support ESM. Ces auteurs devaient soit rompre la compatibilité avec les utilisateurs de CommonJS, soit « publier deux fois » leurs bibliothèques (en fournissant des points d'entrée distincts pour ESM et CommonJS), soit rester indéfiniment sur CommonJS. Bien que la double publication puisse sembler être un bon compromis, il s'agit d'un processus complexe et sujet aux erreurs, qui double également la quantité de code dans un paquetage.

    Node.js 22 assouplit certaines de ces restrictions et autorise les appels require(« esm ») des modules CommonJS vers les modules ECMAScript. Node.js n'autorise toujours pas l'utilisation de require() pour les fichiers ESM qui contiennent une await de premier niveau, mais la plupart des autres fichiers ESM sont désormais consommables à partir des fichiers CommonJS. Cela représente une opportunité majeure pour les auteurs de bibliothèques de fournir un support ESM sans avoir à publier leurs bibliothèques en double.

    TypeScript 5.8 supporte ce comportement avec l'option --module nodenext. Lorsque --module nodenext est activé, TypeScript évitera d'émettre des erreurs sur ces appels require() aux fichiers ESM.

    Parce que cette fonctionnalité peut être rétroportée vers des versions plus anciennes de Node.js, il n'y a actuellement pas d'option stable --module nodeXXXX qui active ce comportement ; cependant, Microsoft prédit que les futures versions de TypeScript pourront stabiliser la fonctionnalité sous node20. En attendant, les utilisateurs de Node.js 22 et plus récents sont encouragés à utiliser --module nodenext, tandis que les auteurs de bibliothèques et les utilisateurs de versions plus anciennes de Node.js devraient continuer à utiliser --module node16 (ou faire la mise à jour mineure vers --module node18).

    --module node18

    TypeScript 5.8 introduit une option stable --module node18. Pour les utilisateurs qui sont fixés sur l'utilisation de Node.js 18, ce drapeau fournit un point de référence stable qui n'incorpore pas certains comportements qui sont dans --module nodenext. En particulier :

    • require() des modules ECMAScript est interdit sous node18, mais autorisé sous nodenext
    • les assertions import (dépréciées en faveur des attributs d'importation) sont autorisées sous node18, mais ne sont pas autorisées sous nodenext

    L'option --erasableSyntaxOnly

    Récemment, Node.js 23.6 a supprimé le support expérimental pour l'exécution directe de fichiers TypeScript ; cependant, seules certaines constructions sont supportées dans ce mode. Node.js a supprimé un mode appelé --experimental-strip-types qui exige que toute syntaxe spécifique à TypeScript ne puisse pas avoir de sémantique d'exécution. En d'autres termes, il doit être possible d'effacer facilement toute syntaxe spécifique à TypeScript d'un fichier, en laissant un fichier JavaScript valide.

    Cela signifie que des constructions comme celles qui suivent ne sont pas prises en charge :

    • déclarations enum
    • namespaces et modules avec code d'exécution
    • propriétés des paramètres dans les classes
    • alias import =

    Voici quelques exemples de ce qui ne fonctionne pas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    //  error: A namespace with runtime code.
    namespace container {
        foo.method();
     
        export type Bar = string;
    }
     
    //  error: An `import =` alias
    import Bar = container.Bar;
     
    class Point {
        //  error: Parameter properties
        constructor(public x: number, public y: number) { }
    }
     
    //  error: An enum declaration.
    enum Direction {
        Up,
        Down,
        Left,
        Right,
    }

    Des outils similaires comme ts-blank-space ou Amaro (la bibliothèque sous-jacente pour la séparation des types dans Node.js) ont les mêmes limitations. Ces outils fourniront des messages d'erreur utiles s'ils rencontrent du code qui ne répond pas à ces exigences, mais l'utilisateur ne découvrira toujours pas que son code ne fonctionne pas tant qu'il n'aura pas essayé de l'exécuter.

    C'est pourquoi TypeScript 5.8 introduit l'option --erasableSyntaxOnly. Lorsque ce drapeau est activé, TypeScript génère des erreurs sur la plupart des constructions spécifiques à TypeScript qui ont un comportement à l'exécution.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class C {
        constructor(public x: number) { }
        //          ~~~~~~~~~~~~~~~~
        // error! This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
        }
    }

    Typiquement, vous voudrez combiner cette option avec --verbatimModuleSyntax, qui garantit qu'un module contient la syntaxe d'importation appropriée, et que l'élision d'importation n'a pas lieu.

    L'option --libReplacement

    Dans TypeScript 4.5, Microsoft a introduit la possibilité de remplacer les fichiers lib par défaut par des fichiers personnalisés. Ceci était basé sur la possibilité de résoudre un fichier de bibliothèque à partir de paquets nommés @typescript/lib-*. Par exemple, vous pouvez verrouiller vos bibliothèques dom sur une version spécifique du package @types/web avec le package.json suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    {
        "devDependencies": {
           "@typescript/lib-dom": "npm:@types/web@0.0.199"
         }
    }

    Une fois installé, un paquetage appelé @typescript/lib-dom devrait exister, et TypeScript le recherchera toujours lorsque dom est impliqué par vos paramètres.

    Il s'agit d'une fonctionnalité puissante, mais qui implique également un peu de travail supplémentaire. Même si vous n'utilisez pas cette fonctionnalité, TypeScript effectue toujours cette recherche et doit surveiller les changements dans node_modules au cas où un paquetage de remplacement de lib commencerait à exister.

    TypeScript 5.8 introduit l'option --libReplacement, qui permet de désactiver ce comportement. Si vous n'utilisez pas --libReplacement, vous pouvez maintenant le désactiver avec --libReplacement false. Dans le futur, --libReplacement false pourrait devenir la valeur par défaut, donc si vous utilisez actuellement ce comportement, vous devriez envisager de l'activer explicitement avec --libReplacement true.


    Conservation des noms de propriété calculés dans les fichiers de déclaration

    Afin de rendre l'émission des propriétés calculées plus prévisible dans les fichiers de déclaration, TypeScript 5.8 préservera systématiquement les noms d'entités (bareVariables et dotted.names.that.look.like.this) dans les noms de propriétés calculées dans les classes.

    Par exemple, considérons le code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    export let propName = "theAnswer";
     
    export class MyClass {
        [propName] = 42;
    //  ~~~~~~~~~~
    // error!
    // A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type.
    }

    Les versions précédentes de TypeScript émettaient une erreur lors de la génération d'un fichier de déclaration pour ce module, et un fichier de déclaration au mieux de sa forme générait une signature d'index.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    export declare let propName: string;
    export declare class MyClass {
        [x: string]: number;
    }

    Dans TypeScript 5.8, l'exemple de code est désormais autorisé et le fichier de déclaration généré correspondra à ce que vous avez écrit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    export declare let propName: string;
    export declare class MyClass {
        [propName]: number;
    }

    Notez que cela ne crée pas de propriétés nommées statiquement sur la classe. Vous obtiendrez toujours ce qui est en fait une signature d'index comme [x : string] : number, donc pour ce cas d'utilisation, vous devrez utiliser unique symbol ou des types littéraux.

    Notez que l'écriture de ce code était et est toujours une erreur sous l'option --isolatedDeclarations ; mais il est prévu que grâce à ce changement, les noms de propriétés calculés seront généralement autorisés dans les déclarations emit.

    Il est possible (bien que peu probable) qu'un fichier compilé en TypeScript 5.8 génère un fichier de déclaration qui n'est pas rétro-compatible avec TypeScript 5.7 ou antérieur.

    Optimisation du chargement et de la mise à jour des programmes

    TypeScript 5.8 introduit un certain nombre d'optimisations qui peuvent à la fois améliorer le temps de construction d'un programme, et également mettre à jour un programme basé sur un changement de fichier, que ce soit en mode --watch ou dans les scénarios de l'éditeur.

    Tout d'abord, TypeScript évite désormais les allocations de tableaux qui seraient nécessaires lors de la normalisation des chemins. Typiquement, la normalisation des chemins implique de segmenter chaque portion d'un chemin en un tableau de chaînes de caractères, de normaliser le chemin résultant sur la base des segments relatifs, puis de les réunir à l'aide d'un séparateur canonique. Pour les projets comportant de nombreux fichiers, cela peut représenter un travail important et répétitif. TypeScript évite désormais d'allouer un tableau et opère plus directement sur les index du chemin d'origine.

    De plus, lorsque des modifications sont apportées sans changer la structure fondamentale d'un projet, TypeScript évite désormais de revalider les options qui lui sont fournies (par exemple, le contenu d'un tsconfig.json). Cela signifie, par exemple, qu'une simple modification peut ne pas nécessiter de vérifier que les chemins de sortie d'un projet n'entrent pas en conflit avec les chemins d'entrée. Au lieu de cela, les résultats de la dernière vérification peuvent être utilisés. Cela devrait permettre aux éditeurs de grands projets d'être plus réactifs.

    Changements de comportement notables

    Cette section présente un ensemble de changements notables qu'il convient de reconnaître et de comprendre dans le cadre d'une mise à jour. Elle met parfois en évidence des dépréciations, des suppressions et de nouvelles restrictions. Elle peut également contenir des corrections de bogues qui sont des améliorations fonctionnelles, mais qui peuvent également affecter une version existante en introduisant de nouvelles erreurs.

    lib.d.ts

    Les types générés pour le DOM peuvent avoir un impact sur la vérification de type de votre base de code. Pour plus d'informations, voir les problèmes liés aux mises à jour de DOM et lib.d.ts pour cette version de TypeScript.

    Restrictions sur les assertions d'importation sous --module nodenext

    Les assertions d'importation étaient un ajout proposé à ECMAScript pour garantir certaines propriétés d'une importation (par exemple, « ce module est JSON, et n'est pas destiné à être du code JavaScript exécutable »). Ils ont été réinventés sous la forme d'une proposition appelée « import attributes » (attributs d'importation). Dans le cadre de la transition, ils sont passés du mot-clé assert au mot-clé with.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    // An import assertion  - not future-compatible with most runtimes.
    import data from "./data.json" assert { type: "json" };
     
    // An import attribute  - the preferred way to import a JSON file.
    import data from "./data.json" with { type: "json" };

    Node.js 22 n'accepte plus les assertions d'importation utilisant la syntaxe assert. Par ailleurs, lorsque l'option --module nodenext est activée dans TypeScript 5.8, TypeScript émettra une erreur s'il rencontre une assertion d'importation.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    import data from "./data.json" assert { type: "json" };
    //                             ~~~~~~
    // error! Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'

    Quelle sera la suite ?

    La prochaine version de TypeScript sera TypeScript 5.9, et les développeurs auront plus de détails grâce à un plan d'itération à venir sur l'issue tracker de Microsoft. Ce plan contiendra des dates précises et plus de détails sur les fonctionnalités à venir sur lesquelles l'équipe de TypeScript prévoit de travailler. En attendant, vous pouvez essayer les premières versions de TypeScript 5.9 dès aujourd'hui en installant les nightly builds depuis npm avec npm install typescript@next, ou en utilisant l'extension VS Code TypeScript Nightly.

    Microsoft conclut : « En attendant, TypeScript 5.8 est là et prêt à l'emploi, et nous sommes impatients que vous l'installiez dès aujourd'hui ! Nous espérons que cette version rendra votre travail de codage quotidien plus agréable. »

    Source : Microsoft

    Et vous ?

    Quel est votre avis sur TypeScript 5.8 ?
    Quelles sont les fonctionnalités que vous aimeriez retrouver dans les futures versions de TypeScript ?

    Voir aussi :

    Microsoft annonce la Release Candidate de TypeScript 5.8, et apporte des vérifications plus granulaires pour les branches dans les expressions de retour

    Microsoft annonce la disponibilité de TypeScript 5.8 Beta avec plusieurs améliorations, dont une meilleure vérification des types de retours pour les types d'accès conditionnels et indexés

    Microsoft annonce la disponibilité de TypeScript 5.6, apportant des améliorations à la vérification vraie et nulle non autorisée ainsi que des méthodes d'aide pour les itérateurs
    Contribuez au club : corrections, suggestions, critiques, ... Contactez le service news et Rédigez des actualités

Discussions similaires

  1. Microsoft annonce la disponibilité de TypeScript 5.7 Beta
    Par Jade Emy dans le forum TypeScript
    Réponses: 2
    Dernier message: 26/11/2024, 15h28
  2. Microsoft annonce la disponibilité de TypeScript 5.5 Beta
    Par Jade Emy dans le forum TypeScript
    Réponses: 3
    Dernier message: 21/06/2024, 10h35
  3. Microsoft annonce la disponibilité de TypeScript 5.4 Beta
    Par Jade Emy dans le forum TypeScript
    Réponses: 2
    Dernier message: 07/03/2024, 12h53
  4. Microsoft annonce la disponibilité de TypeScript 5.2 Beta.
    Par Nancy Rey dans le forum TypeScript
    Réponses: 2
    Dernier message: 10/08/2023, 11h46
  5. Réponses: 0
    Dernier message: 23/02/2017, 13h12

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo