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.4 Beta


Sujet :

TypeScript

  1. #1
    Communiqués de presse

    Femme Profil pro
    Traductrice Technique
    Inscrit en
    Juin 2023
    Messages
    942
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France

    Informations professionnelles :
    Activité : Traductrice Technique

    Informations forums :
    Inscription : Juin 2023
    Messages : 942
    Points : 66 353
    Points
    66 353
    Par défaut Microsoft annonce la disponibilité de TypeScript 5.4 Beta
    Microsoft annonce la disponibilité de TypeScript 5.4 Beta, avec l'introduction du type utilitaire NoInfer, mais aussi les changements à venir suite aux dépréciations de TypeScript 5.0

    Voici la présentation de TypeScript 5.4 Beta. Parmi les nouveautés : préservation du rétrécissement dans les fermetures suivant les dernières affectations, le type utilitaire NoInfer, le support des appels require() dans --moduleResolution bundler et --module preserve, et bien d'autres. Microsoft annonce aussi les changements à venir de la version 5.5 suite aux dépréciations de TypeScript 5.0.

    Nom : 1.PNG
Affichages : 12163
Taille : 42,6 Ko

    Préservation du rétrécissement dans les fermetures après les dernières affectations

    TypeScript peut généralement déterminer un type plus spécifique pour une variable en se basant sur les vérifications que vous pouvez effectuer. Ce processus est appelé rétrécissement.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    function uppercaseStrings(x: string | number) {
        if (typeof x === "string") {
            // TypeScript knows 'x' is a 'string' here.
            return x.toUpperCase();
        }
    }
    Un problème courant était que ces types restreints n'étaient pas toujours préservés dans les fermetures de fonctions.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    function getUrls(url: string | URL, names: string[]) {
        if (typeof url === "string") {
            url = new URL(url);
        }
     
        return names.map(name => {
            url.searchParams.set("name", name)
            //  ~~~~~~~~~~~~
            // error!
            // Property 'searchParams' does not exist on type 'string | URL'.
     
            return url.toString();
        });
    }
    Ici, TypeScript a décidé qu'il n'était pas "sûr" de supposer que url était en fait un objet URL dans la fonction de rappel parce qu'il a été muté ailleurs ; cependant, dans ce cas, cette fonction arrow est toujours créée après l'affectation à url, et c'est aussi la dernière affectation à url.

    TypeScript 5.4 tire parti de cette situation pour rendre le rétrécissement un peu plus intelligent. Lorsque des paramètres et des variables let sont utilisés dans des fonctions non hoisies, le vérificateur de type recherche un dernier point d'affectation. S'il en trouve un, TypeScript peut, en toute sécurité, rétrécir à partir de l'extérieur de la fonction contenante. Cela signifie que l'exemple ci-dessus fonctionne maintenant.

    Notez que l'analyse de rétrécissement n'intervient pas si la variable est assignée n'importe où dans une fonction imbriquée. En effet, il n'y a aucun moyen de savoir avec certitude si la fonction sera appelée plus tard.

    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
    function printValueLater(value: string | undefined) {
        if (value === undefined) {
            value = "missing!";
        }
     
        setTimeout(() => {
            // Modifying 'value', even in a way that shouldn't affect
            // its type, will invalidate type refinements in closures.
            value = value;
        }, 500);
     
        setTimeout(() => {
            console.log(value.toUpperCase());
            //          ~~~~~
            // error! 'value' is possibly 'undefined'.
        }, 1000);
    }
    Cela devrait faciliter l'expression de nombreux codes JavaScript typiques.


    Le type utilitaire NoInfer

    Lors de l'appel de fonctions génériques, TypeScript est capable de déduire le type des arguments à partir de ce que vous lui passez.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function doSomething<T>(arg: T) {
        // ...
    }
     
     
    // We can explicitly say that 'T' should be 'string'.
    doSomething<string>("hello!");
     
    // We can also just let the type of 'T' get inferred.
    doSomething("hello!");
    Cependant, il n'est pas toujours évident de savoir quel est le "meilleur" type à déduire. Cela peut conduire TypeScript à rejeter des appels valides, à accepter des appels douteux, ou tout simplement à envoyer des messages d'erreur plus mauvais lorsqu'il détecte un bogue.

    Par exemple, imaginons une fonction createStreetLight qui prend une liste de noms de couleurs, ainsi qu'une couleur par défaut optionnelle.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    function createStreetLight<C extends string>(colors: C[], defaultColor?: C) {
        // ...
    }
     
    createStreetLight(["red", "yellow", "green"], "red");
    Que se passe-t-il lorsqu'on passe à defaultColor qui n'était pas dans le tableau de colors d'origine ? Dans cette fonction, colors est censé être la "source de vérité" et décrire ce qui peut être passé à defaultColor.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    // Oops! This undesirable, but is allowed!
    createStreetLight(["red", "yellow", "green"], "blue");
    Dans cet appel, l'inférence de type a décidé que "blue" était un type tout aussi valide que "red" ou "yellow" ou "green". Ainsi, au lieu de rejeter l'appel, TypeScript déduit le type de C comme étant "rouge" | "jaune" | "vert" | "bleu". On pourrait dire que l'inférence est apparue comme un bleu dans la figure !

    L'une des façons de résoudre ce problème est d'ajouter un paramètre de type séparé qui est délimité par le paramètre de type existant.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    function createStreetLight<C extends string, D extends C>(colors: C[], defaultColor?: D) {
    }
     
    createStreetLight(["red", "yellow", "green"], "blue");
    //                                            ~~~~~~
    // error!
    // Argument of type '"blue"' is not assignable to parameter of type '"red" | "yellow" | "green" | undefined'.
    Cela fonctionne, mais c'est un peu gênant car D ne sera probablement utilisé nulle part ailleurs dans la signature de createStreetLight. Bien que ce ne soit pas mauvais dans ce cas, l'utilisation d'un paramètre de type une seule fois dans une signature est souvent une odeur de code.

    C'est pourquoi TypeScript 5.4 introduit un nouveau type utilitaire NoInfer<T>. Entourer un type de NoInfer<...> indique à TypeScript de ne pas creuser et de ne pas comparer les types internes pour trouver des candidats à l'inférence de type.

    En utilisant NoInfer, on peut réécrire createStreetLight comme suit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    function createStreetLight<C extends string>(colors: C[], defaultColor?: NoInfer<C>) {
        // ...
    }
     
    createStreetLight(["red", "yellow", "green"], "blue");
    //                                            ~~~~~~
    // error!
    // Argument of type '"blue"' is not assignable to parameter of type '"red" | "yellow" | "green" | undefined'.
    Exclure le type defaultColor de l'exploration pour l'inférence signifie que "blue" ne se retrouve jamais comme candidat à l'inférence, et que le vérificateur de type peut le rejeter.


    Object.groupBy et Map.groupBy

    TypeScript 5.4 ajoute des déclarations pour les nouvelles méthodes statiques JavaScript Object.groupBy et Map.groupBy.

    Object.groupBy prend un itérable et une fonction qui décide dans quel "groupe" chaque élément doit être placé. La fonction doit créer une "clé" pour chaque groupe distinct, et Object.groupBy utilise cette clé pour créer un objet où chaque clé correspond à un tableau contenant l'élément original.

    Voici donc le JavaScript suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    const array = [0, 1, 2, 3, 4, 5];
     
    const myObj = Object.groupBy(array, (num, index) => {
        return num % 2 === 0 ? "even": "odd";
    });
    équivaut en fait à écrire ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    const myObj = {
        even: [0, 2, 4],
        odd: [1, 3, 5],
    };
    Map.groupBy est similaire, mais produit une map au lieu d'un simple objet. Cela peut être plus souhaitable si vous avez besoin des garanties de Map, si vous travaillez avec des API qui attendent des Map, ou si vous avez besoin d'utiliser n'importe quel type de clé pour le regroupement - et pas seulement les clés qui peuvent être utilisées comme noms de propriétés en JavaScript.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    const myObj = Map.groupBy(array, (num, index) => {
        return num % 2 === 0 ? "even" : "odd";
    });
    et comme précédemment, vous auriez pu créer myObj d'une manière équivalente :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    const myObj = new Map();
     
    myObj.set("even", [0, 2, 4]);
    myObj.set("odd", [1, 3, 5]);
    Notez que dans l'exemple ci-dessus d'Object.groupBy, l'objet produit utilise toutes les propriétés optionnelles.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    interface EvenOdds {
        even?: number[];
        odd?: number[];
    }
     
    const myObj: EvenOdds = Object.groupBy(...);
     
    myObj.even;
    //    ~~~~
    // Error to access this under 'strictNullChecks'.
    Ceci est dû au fait qu'il n'y a aucun moyen de garantir de manière générale que toutes les clés ont été produites par groupBy.

    Notez également que ces méthodes ne sont accessibles qu'en configurant target à esnext ou en ajustant les paramètres de lib. Microsoft espère qu'elles seront éventuellement disponibles sous une cible stable es2024.


    Support des appels require() dans --moduleResolution bundler et --module preserve

    TypeScript dispose d'une option moduleResolution appelée bundler qui est censée modéliser la façon dont les bundlers modernes déterminent à quel fichier un chemin d'importation fait référence. L'une des limitations de cette option est qu'elle doit être associée à --module esnext, ce qui rend impossible l'utilisation de la syntaxe import ... = require(...).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    // previously errored
    import myModule = require("module/path");
    Cela peut sembler anodin si vous prévoyez d'écrire des importations ECMAScript standard, mais il y a une différence lorsque vous utilisez un package avec des exportations conditionnelles.

    Dans TypeScript 5.4, require() peut désormais être utilisé pour définir le paramètre de module avec une nouvelle option appelée preserve.

    Entre --module preserve et --moduleResolution bundler, les deux modélisent plus précisément ce que les bundlers et les runtimes comme Bun autoriseront, et comment ils effectueront les recherches de modules. En fait, en utilisant --module preserve, l'option bundler sera implicitement définie pour --moduleResolution (avec --esModuleInterop et --resolveJsonModule).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    {
        "compilerOptions": {
            "module": "preserve",
            // ^ also implies:
            // "moduleResolution": "bundler",
            // "esModuleInterop": true,
            // "resolveJsonModule": true,
     
            // ...
        }
    }
    Sous --module preserve, un import ECMAScript sera toujours émis tel quel, et import ... = require(...) sera émis comme un appel à require() (bien qu'en pratique vous puissiez ne pas utiliser TypeScript pour emit, puisqu'il est probable que vous utilisiez un bundler pour votre code). Ceci est vrai quelle que soit l'extension du fichier contenant le code. Ainsi, la sortie de ce code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    import * as foo from "some-package/foo";
    import bar = require("some-package/bar");
    devrait ressembler à ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    import * as foo from "some-package/foo";
    var bar = require("some-package/bar");
    Cela signifie également que la syntaxe que vous choisissez détermine la manière dont les exportations conditionnelles sont prises en compte. Ainsi, dans l'exemple ci-dessus, si le package.json de some-package ressemble à ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    {
      "name": "some-package",
      "version": "0.0.1",
      "exports": {
        "./foo": {
            "import": "./esm/foo-from-import.mjs",
            "require": "./cjs/foo-from-require.cjs"
        },
        "./bar": {
            "import": "./esm/bar-from-import.mjs",
            "require": "./cjs/bar-from-require.cjs"
        }
      }
    }
    TypeScript résoudra ces chemins en [...]/some-package/esm/foo-from-import.mjs et [...]/some-package/cjs/bar-from-require.cjs.


    Attributs et assertions d'importation vérifiés

    Les attributs et assertions d'importation sont désormais vérifiés par rapport au type global ImportAttributes. Cela signifie que les moteurs d'exécution peuvent maintenant décrire plus précisément les attributs d'importation.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // In some global file.
    interface ImportAttributes {
        type: "json";
    }
     
    // In some other module
    import * as ns from "foo" with { type: "not-json" };
    //                                     ~~~~~~~~~~
    // error!
    //
    // Type '{ type: "not-json"; }' is not assignable to type 'ImportAttributes'.
    //  Types of property 'type' are incompatible.
    //    Type '"not-json"' is not assignable to type '"json"'.

    Correction rapide pour l'ajout de paramètres manquants

    TypeScript dispose désormais d'une solution rapide pour ajouter un nouveau paramètre aux fonctions qui sont appelées avec trop d'arguments.

    Nom : 2.PNG
Affichages : 1837
Taille : 59,3 Ko

    Cela peut être utile pour faire passer un nouvel argument à travers plusieurs fonctions existantes, ce qui peut être encombrant aujourd'hui.


    Changements à venir suite aux dépréciations de TypeScript 5.0

    TypeScript 5.0 a rendu obsolètes les options et comportements suivants :

    • target: ES3
    • noImplicitUseStrict
    • keyofStringsOnly
    • suppressExcessPropertyErrors
    • suppressImplicitAnyIndexErrors
    • noStrictGenericChecks
    • charset
    • out
    • prepend pour les projets références
    • newLine implicitement spécifique à l'OS

    Pour continuer à les utiliser, les développeurs utilisant TypeScript 5.0 et d'autres versions plus récentes ont dû spécifier une nouvelle option appelée ignoreDeprecations avec la valeur "5.0".

    Cependant, TypScript 5.4 sera la dernière version dans laquelle ils continueront à fonctionner normalement. D'ici TypeScript 5.5 (probablement juin 2024), elles deviendront des erreurs difficiles à corriger, et le code qui les utilise devra être migré.


    Changements en cours

    Changements dans lib.d.ts

    Les types générés pour le DOM peuvent avoir un impact sur votre base de code.

    Contraintes de type conditionnel plus précises

    Le code suivant n'autorise plus la deuxième déclaration de variable dans la fonction foo.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    type IsArray<T> = T extends any[] ? true : false;
     
    function foo<U extends object>(x: IsArray<U>) {
        let first: true = x;   // Error
        let second: false = x;  // Error, but previously wasn't
    }
    Auparavant, lorsque TypeScript vérifiait l'initialisateur pour la second, il devait déterminer si IsArray<U> était assignable au type unitaire false. Bien que IsArray<U> ne soit pas compatible de manière évidente, TypeScript examine également la contrainte de ce type. Dans un type conditionnel comme T extends Foo ? TrueBranch : FalseBranch, où T est générique, le système de type regarderait la contrainte de T, la substituerait à T lui-même, et déciderait de la branche vraie ou fausse.

    Mais ce comportement était inexact car il était trop enthousiaste. Même si la contrainte de T n'est pas assignable à Foo, cela ne signifie pas qu'elle ne sera pas instanciée avec quelque chose qui l'est. Le comportement le plus correct est donc de produire un type union pour la contrainte du type conditionnel dans les cas où il n'est pas possible de prouver que T n'étend jamais ou toujours Foo.

    TypeScript 5.4 adopte ce comportement plus précis. En pratique, cela signifie que certaines instances de types conditionnels ne sont plus compatibles avec leurs branches.

    Réduction plus agressive des intersections entre les variables de type et les types primitifs

    TypeScript réduit maintenant les intersections entre les variables de type et les primitives de manière plus agressive, en fonction de la façon dont la contrainte de la variable de type se superpose à ces primitives.

    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
    declare function intersect<T, U>(x: T, y: U): T & U;
     
    function foo<T extends "abc" | "def">(x: T, str: string, num: number) {
     
        // Was 'T & string', now is just 'T'
        let a = intersect(x, str);
     
        // Was 'T & number', now is just 'never'
        let b = intersect(x, num)
     
        // Was '(T & "abc") | (T & "def")', now is just 'T'
        let c = Math.random() < 0.5 ?
            intersect(x, "abc") :
            intersect(x, "def");
    }
    TypeScript vérifie désormais plus précisément si les chaînes de caractères sont assignables ou non aux emplacements d'un type de chaîne de caractères template.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    function a<T extends {id: string}>() {
        let x: `-${keyof T & string}`;
     
        // Used to error, now doesn't.
        x = "-id";
    }
    Ce comportement est plus souhaitable, mais peut causer des ruptures dans le code utilisant des constructions comme les types conditionnels, où ces changements de règles sont faciles à observer.

    Erreurs lorsque les importations de type seulement entrent en conflit avec les valeurs locales

    Auparavant, TypeScript autorisait le code suivant sous isolatedModules si l'importation vers Something ne faisait référence qu'à un type.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    import { Something } from "./some/path";
     
    let Something = 123;
    Cependant, il n'est pas sûr pour un compilateur à fichier unique de supposer qu'il est "sûr" d'abandonner l'importation, même si le code est garanti d'échouer à l'exécution. Dans TypeScript 5.4, ce code déclenchera une erreur comme la suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Import 'Something' conflicts with local value, so must be declared with a type-only import when 'isolatedModules' is enabled.
    La solution consiste soit à effectuer un renommage local, soit, comme l'indique l'erreur, à ajouter le modificateur de type à l'importation :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    import type { Something } from "./some/path";
     
    // or
     
    import { type Something } from "./some/path";
    Émettre des modifications

    Bien qu'il ne s'agisse pas d'un changement radical en soi, les développeurs peuvent avoir implicitement pris des dépendances sur les sorties d'émission de JavaScript ou de déclaration de TypeScript. Les changements suivants sont notables.

    • Préserver plus souvent les noms des paramètres de type lorsqu'ils sont masqués.
    • Déplacer les listes de paramètres complexes des fonctions asynchrones dans le corps du générateur de niveau inférieur.
    • Ne pas supprimer l'alias de liaison dans les déclarations de fonction
    • Les ImportAttributes devraient passer par les mêmes phases d'émission lorsqu'ils se trouvent dans un ImportTypeNode.


    Quelles sont les prochaines étapes ?

    À ce stade, TypeScript 5.4 est ce qu'on appelle "stable en termes de fonctionnalités". TypeScript 5.4 se concentrera sur les corrections de bogues, le polissage et certaines fonctionnalités d'édition à faible risque. Une version candidate sera disponible dans un peu plus d'un mois, suivie d'une version stable peu après. Si vous souhaitez planifier la sortie de cette version, n'oubliez pas de garder un œil sur notre plan d'itération qui indique les dates de sortie et bien d'autres choses encore.

    Remarque : bien que la version bêta soit un excellent moyen d'essayer la prochaine version de TypeScript, vous pouvez également essayer une version de nuit pour obtenir la version la plus récente de TypeScript 5.4 jusqu'à notre candidat à la publication. Nos nightlies sont bien testées et peuvent même être testées uniquement dans votre éditeur.

    Alors n'hésitez pas à essayer la version bêta ou une version de nuit dès aujourd'hui et faites-nous savoir ce que vous en pensez !
    Sources : Daniel Rosenwasser et l'équipe TypeScript

    Et vous ?

    Quel est votre avis sur cette mise à jour de TypeScript ?

    Voir aussi :

    Cinq vérités inconfortables à propos de TypeScript selon Stefan Baumgartner, auteur de livres sur le langage de programmation

    Microsoft annonce la disponibilité de TypeScript 5.3 Release Candidate, documentant le resolution-mode et ajoutant une option de préférence pour l'importation automatique des Type

    TypeScript a 10 ans ! Joyeux anniversaire. À cette occasion, Microsoft fait le point. L'entreprise revient sur les doutes des premiers jours ainsi que sur l'évolution du langage
    Publication de communiqués de presse en informatique. Contribuez au club : corrections, suggestions, critiques, ... Contactez le service news et Rédigez des actualités

  2. #2
    Communiqués de presse

    Femme Profil pro
    Traductrice Technique
    Inscrit en
    Juin 2023
    Messages
    942
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France

    Informations professionnelles :
    Activité : Traductrice Technique

    Informations forums :
    Inscription : Juin 2023
    Messages : 942
    Points : 66 353
    Points
    66 353
    Par défaut Microsoft annonce la disponibilité de la version candidate de TypeScript 5.4
    Microsoft annonce la disponibilité de la version candidate de TypeScript 5.4, cette version corrige des bogues critiques et contient des changements notables de comportement

    Après la version Beta de TypeScript 5.4, voici la présentation de la version candidate de TypeScript 5.4 (TypeScript 5.4 RC). Cette version se concentre sur les corrections de bogues. D'ici la sortie de la version stable de TypeScript 5.4, Microsoft ne prévoit pas d'autres changements, que des corrections de bogues critiques.

    Voici une liste rapide des nouveautés de TypeScript 5.4 :

    • Préservation du rétrécissement dans les fermetures après les dernières affectations
    • Le type utilitaire NoInfer
    • Object.groupBy et Map.groupBy
    • Support des appels require() dans --moduleResolution bundler et --module preserve
    • Attributs et assertions d'importation vérifiés
    • Correction rapide pour l'ajout de paramètres manquants
    • Dépréciations à venir de la version 5.5


    Ces nouveautés n'ont subit aucun changement dans cette version stable. Depuis la bêta, cette version met à jour les nouveaux changements notables de comportement, y compris les restrictions autour de la compatibilité des enums, les restrictions sur le nommage des membres des enums, et les améliorations dans le comportement des types mappés.

    Nom : 2.png
Affichages : 11023
Taille : 42,6 Ko

    Changements à venir suite aux dépréciations de TypeScript 5.0

    TypeScript 5.0 a rendu obsolètes les options et comportements suivants :

    • charset
    • target: ES3
    • importsNotUsedAsValues
    • noImplicitUseStrict
    • noStrictGenericChecks
    • keyofStringsOnly
    • suppressExcessPropertyErrors
    • suppressImplicitAnyIndexErrors
    • out
    • preserveValueImports
    • prepend pour les projets références
    • newLine inmplicitemet spécifique à l'OS

    Pour continuer à les utiliser, les développeurs utilisant TypeScript 5.0 et d'autres versions plus récentes ont dû spécifier une nouvelle option appelée ignoreDeprecations avec la valeur "5.0".

    Cependant, TypScript 5.4 sera la dernière version dans laquelle elles continueront à fonctionner normalement. D'ici TypeScript 5.5 (probablement juin 2024), elles deviendront des erreurs difficiles à corriger, et le code qui les utilise devra être migré.


    Changements notables du comportement

    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.


    Changements dans 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.


    Contraintes de type conditionnelles plus précises

    Le code suivant n'autorise plus la deuxième déclaration de variable dans la fonction foo.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    type IsArray<T> = T extends any[] ? true : false;
     
    function foo<U extends object>(x: IsArray<U>) {
        let first: true = x;    // Error
        let second: false = x;  // Error, but previously wasn't
    }
    Auparavant, lorsque TypeScript vérifiait l'initialisateur pour second, il devait déterminer si IsArray<U> était assignable au type unitaire false. Bien que IsArray<U> ne soit pas compatible de manière évidente, TypeScript examine également la contrainte de ce type. Dans un type conditionnel comme T extends Foo ? TrueBranch : FalseBranch, où T est générique, le système de type regarderait la contrainte de T, la substituerait à T lui-même, et déciderait de la branche vraie ou fausse.

    Mais ce comportement était inexact car il était trop enthousiaste. Même si la contrainte de T n'est pas assignable à Foo, cela ne signifie pas qu'elle ne sera pas instanciée avec quelque chose qui l'est. Le comportement le plus correct est donc de produire un type union pour la contrainte du type conditionnel dans les cas où il n'est pas possible de prouver que T n'étend jamais ou toujours Foo.

    TypeScript 5.4 adopte ce comportement plus précis. Ce que cela signifie en pratique, c'est que vous pouvez commencer à trouver que certaines instances de type conditionnel ne sont plus compatibles avec leurs branches.


    Réduction plus agressive des intersections entre les variables de type et les types primitifs

    TypeScript réduit maintenant les intersections entre les variables de type et les primitives de manière plus agressive, en fonction de la façon dont la contrainte de la variable de type se superpose à ces primitives.

    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
    declare function intersect<T, U>(x: T, y: U): T & U;
     
    function foo<T extends "abc" | "def">(x: T, str: string, num: number) {
     
        // Was 'T & string', now is just 'T'
        let a = intersect(x, str);
     
        // Was 'T & number', now is just 'never'
        let b = intersect(x, num)
     
        // Was '(T & "abc") | (T & "def")', now is just 'T'
        let c = Math.random() < 0.5 ?
            intersect(x, "abc") :
            intersect(x, "def");
    }


    Amélioration de la vérification des chaînes de caractères avec interpolations

    TypeScript vérifie maintenant plus précisément si les chaînes de caractères sont assignables aux emplacements d'un modèle de chaîne de caractères.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    function a<T extends {id: string}>() {
        let x: `-${keyof T & string}`;
     
        // Used to error, now doesn't.
        x = "-id";
    }
    Ce comportement est plus souhaitable, mais peut causer des ruptures dans le code utilisant des constructions comme les types conditionnels, où ces changements de règles sont faciles à observer.


    Erreurs lorsque les importations de type seulement entrent en conflit avec les valeurs locales

    Auparavant, TypeScript autorisait le code suivant sous isolatedModules si l'importation vers Something ne faisait référence qu'à un type.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    import { Something } from "./some/path";
     
    let Something = 123;
    Cependant, il n'est pas sûr pour un compilateur à fichier unique de supposer qu'il est "sûr" d'abandonner l'importation, même si le code est garanti d'échouer à l'exécution. Dans TypeScript 5.4, ce code déclenchera une erreur comme la suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Import 'Something' conflicts with local value, so must be declared with a type-only import when 'isolatedModules' is enabled.
    La solution consiste soit à effectuer un renommage local, soit, comme l'indique l'erreur, à ajouter le modificateur de type à l'importation :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    import type { Something } from "./some/path";
     
    // or
     
    import { type Something } from "./some/path";


    Nouvelles restrictions d'assignabilité des enums

    Lorsque deux enums ont les mêmes noms déclarés et les mêmes noms de membres d'enum, ils étaient auparavant toujours considérés comme compatibles ; cependant, lorsque les valeurs étaient connues, TypeScript autorisait silencieusement qu'ils aient des valeurs différentes.

    TypeScript 5.4 renforce cette restriction en exigeant que les valeurs soient identiques lorsqu'elles sont connues.

    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
    namespace First {
        export enum SomeEnum {
            A = 0,
            B = 1,
        }
    }
     
    namespace Second {
        export enum SomeEnum {
            A = 0,
            B = 2,
        }
    }
     
    function foo(x: First.SomeEnum, y: Second.SomeEnum) {
        // Both used to be compatible - no longer the case,
        // TypeScript errors with something like:
        //
        //  Each declaration of 'SomeEnum.B' differs in its value, where '1' was expected but '2' was given.
        x = y;
        y = x;
    }
    De plus, il existe de nouvelles restrictions pour les cas où l'un des membres de l'énumération n'a pas de valeur statiquement connue. Dans ce cas, l'autre enum doit au moins être implicitement numérique (par exemple, il n'a pas d'initialisateur résolu statiquement), ou il est explicitement numérique (ce qui signifie que TypeScript pourrait résoudre la valeur en quelque chose de numérique). En pratique, cela signifie que les membres d'une énumération de chaînes de caractères ne sont jamais compatibles qu'avec d'autres énumérations de chaînes de caractères de même valeur.

    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
    namespace First {
        export declare enum SomeEnum {
            A,
            B,
        }
    }
     
    namespace Second {
        export declare enum SomeEnum {
            A,
            B = "some known string",
        }
    }
     
    function foo(x: First.SomeEnum, y: Second.SomeEnum) {
        // Both used to be compatible - no longer the case,
        // TypeScript errors with something like:
        //
        //  One value of 'SomeEnum.B' is the string '"some known string"', and the other is assumed to be an unknown numeric value.
        x = y;
        y = x;
    }


    Restrictions sur les noms des membres des enums

    TypeScript ne permet plus aux membres d'une énumération d'utiliser les noms Infinity, -Infinity ou NaN.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    // Errors on all of these:
    //
    //  An enum member cannot have a numeric name.
    enum E {
        Infinity = 0,
        "-Infinity" = 1,
        NaN = 2,
    }


    Meilleure préservation des types mappés sur les tuples avec n'importe quels éléments restants

    Auparavant, l'application d'un type mappé avec any dans un tuple créait un type d'élément any. Ceci n'est pas souhaitable et est maintenant corrigé.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Promise.all(["", ...([] as any)])
        .then((result) => {
            const head = result[0];       // 5.3: any, 5.4: string
            const tail = result.slice(1); // 5.3 any, 5.4: any[]
        });


    Quelles sont les prochaines étapes ?

    À ce stade, nous prévoyons très peu de changements pour TypeScript 5.4, hormis des corrections de bogues critiques pour le compilateur et des corrections de bogues mineurs pour le service de langage. Dans les prochaines semaines, nous publierons la première version stable de TypeScript 5.4. Gardez un œil sur notre plan d'itération pour connaître les dates de sortie et plus si vous avez besoin de planifier en fonction de cela.

    Sinon, nous nous concentrons principalement sur le développement de TypeScript 5.5, et nous venons de rendre public le plan d'itération de TypeScript 5.5. De même, ce plan d'itération décrit les domaines d'intérêt et les éléments de travail prévus, ainsi que les dates de publication cibles que vous pouvez utiliser pour vos propres plans. 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.
    Source : Daniel Rosenwasser et l'équipe TypeScript

    Et vous ?

    Quel est votre avis sur cette version ?

    Voir aussi :

    Microsoft annonce la disponibilité de TypeScript 5.4 Beta, avec l'introduction du type utilitaire NoInfer, mais aussi les changements à venir suite aux dépréciations de TypeScript 5.0

    TypeScript a 10 ans ! Joyeux anniversaire. À cette occasion, Microsoft fait le point. L'entreprise revient sur les doutes des premiers jours ainsi que sur l'évolution du langage

    Cinq vérités inconfortables à propos de TypeScript selon Stefan Baumgartner, auteur de livres sur le langage de programmation
    Publication de communiqués de presse en informatique. Contribuez au club : corrections, suggestions, critiques, ... Contactez le service news et Rédigez des actualités

  3. #3
    Communiqués de presse

    Femme Profil pro
    Traductrice Technique
    Inscrit en
    Juin 2023
    Messages
    942
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France

    Informations professionnelles :
    Activité : Traductrice Technique

    Informations forums :
    Inscription : Juin 2023
    Messages : 942
    Points : 66 353
    Points
    66 353
    Par défaut Microsoft annonce la disponibilité de la version stable de TypeScript 5.4
    Microsoft annonce la disponibilité de la version stable de TypeScript 5.4, cette version apporte un nouveau support d'auto-importation pour les importations de sous-chemins

    Microsoft annonce la disponibilité de la version stable de TypeScript 5.4. Voici la documentation complète des nouvelles fonctionnalités et des corrections de bogues dans TypeScript 5.4.

    Si vous ne connaissez pas TypeScript, il s'agit d'un langage qui s'appuie sur JavaScript en permettant de déclarer et de décrire des types. Écrire des types dans un 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 bien plus encore. Les types alimentent également les outils d'édition de TypeScript tels que l'auto-complétion, la navigation dans le code et les refactorisations qu'on peut voir dans Visual Studio et VS Code. En fait, si vous avez écrit du JavaScript dans l'un ou l'autre de ces éditeurs, vous avez utilisé TypeScript pendant tout ce temps.

    Pour commencer à utiliser TypeScript via NuGet ou via npm avec la commande suivante :

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

    Voici une liste rapide des nouveautés de TypeScript 5.4 :

    • Préservation du rétrécissement dans les fermetures suivant les dernières affectations
    • Le type utilitaire NoInfer
    • Object.groupBy et Map.groupBy
    • Support des appels require() dans --moduleResolution bundler et --module preserve
    • Attributs et assertions d'importation vérifiés
    • Correction rapide pour l'ajout de paramètres manquants
    • Support de l'auto-importation pour les importations de sous-chemins
    • Dépréciations 5.5 à venir
    • Changements notables de comportement


    Quelles sont les nouveautés depuis la version bêta et la version candidate (RC) ?

    Depuis la bêta, la version candidate (RC) a mis à jour les nouveaux changements notables de comportement, y compris les restrictions autour de la compatibilité des enums, les restrictions sur le nommage des membres des enums, et les améliorations dans le comportement des types mappés.

    Depuis la version candidate, il y a maintenant un nouveau support d'auto-importation pour les importations de sous-chemins.

    Nom : 1.png
Affichages : 16055
Taille : 42,6 Ko

    Préservation du rétrécissement dans les fermetures après les dernières affectations

    TypeScript peut généralement déterminer un type plus spécifique pour une variable en se basant sur les vérifications que vous pouvez effectuer. Ce processus est appelé rétrécissement.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    function uppercaseStrings(x: string | number) {
        if (typeof x === "string") {
            // TypeScript knows 'x' is a 'string' here.
            return x.toUpperCase();
        }
    }
    Un problème courant était que ces types restreints n'étaient pas toujours préservés dans les fermetures de fonctions.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    function getUrls(url: string | URL, names: string[]) {
        if (typeof url === "string") {
            url = new URL(url);
        }
     
        return names.map(name => {
            url.searchParams.set("name", name)
            //  ~~~~~~~~~~~~
            // error!
            // Property 'searchParams' does not exist on type 'string | URL'.
     
            return url.toString();
        });
    }
    Ici, TypeScript a décidé qu'il n'était pas "sûr" de supposer que url était en fait un objet URL dans la fonction de rappel parce qu'il a été muté ailleurs ; cependant, dans ce cas, cette fonction arrow est toujours créée après l'affectation à url, et c'est aussi la dernière affectation à url.

    TypeScript 5.4 tire parti de cette situation pour rendre le rétrécissement un peu plus intelligent. Lorsque des paramètres et des variables let sont utilisés dans des fonctions non hoisies, le vérificateur de type recherche un dernier point d'affectation. S'il en trouve un, TypeScript peut, en toute sécurité, rétrécir à partir de l'extérieur de la fonction contenante. Cela signifie que l'exemple ci-dessus fonctionne maintenant.

    Notez que l'analyse de rétrécissement n'intervient pas si la variable est assignée n'importe où dans une fonction imbriquée. En effet, il n'y a aucun moyen de savoir avec certitude si la fonction sera appelée plus tard.

    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
    function printValueLater(value: string | undefined) {
        if (value === undefined) {
            value = "missing!";
        }
     
        setTimeout(() => {
            // Modifying 'value', even in a way that shouldn't affect
            // its type, will invalidate type refinements in closures.
            value = value;
        }, 500);
     
        setTimeout(() => {
            console.log(value.toUpperCase());
            //          ~~~~~
            // error! 'value' is possibly 'undefined'.
        }, 1000);
    }
    Cela devrait faciliter l'expression de nombreux codes JavaScript typiques.


    Le type utilitaire NoInfer

    Lors de l'appel de fonctions génériques, TypeScript est capable de déduire le type des arguments à partir de ce que vous lui passez.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function doSomething<T>(arg: T) {
        // ...
    }
     
     
    // We can explicitly say that 'T' should be 'string'.
    doSomething<string>("hello!");
     
    // We can also just let the type of 'T' get inferred.
    doSomething("hello!");
    Cependant, il n'est pas toujours évident de savoir quel est le "meilleur" type à déduire. Cela peut conduire TypeScript à rejeter des appels valides, à accepter des appels douteux, ou tout simplement à envoyer des messages d'erreur plus mauvais lorsqu'il détecte un bogue.

    Par exemple, imaginons une fonction createStreetLight qui prend une liste de noms de couleurs, ainsi qu'une couleur par défaut optionnelle.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    function createStreetLight<C extends string>(colors: C[], defaultColor?: C) {
        // ...
    }
     
    createStreetLight(["red", "yellow", "green"], "red");
    Que se passe-t-il lorsqu'on passe à defaultColor qui n'était pas dans le tableau de colors d'origine ? Dans cette fonction, colors est censé être la "source de vérité" et décrire ce qui peut être passé à defaultColor.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    // Oops! This undesirable, but is allowed!
    createStreetLight(["red", "yellow", "green"], "blue");
    Dans cet appel, l'inférence de type a décidé que "blue" était un type tout aussi valide que "red" ou "yellow" ou "green". Ainsi, au lieu de rejeter l'appel, TypeScript déduit le type de C comme étant "rouge" | "jaune" | "vert" | "bleu". On pourrait dire que l'inférence est apparue comme un bleu dans la figure !

    L'une des façons de résoudre ce problème est d'ajouter un paramètre de type séparé qui est délimité par le paramètre de type existant.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    function createStreetLight<C extends string, D extends C>(colors: C[], defaultColor?: D) {
    }
     
    createStreetLight(["red", "yellow", "green"], "blue");
    //                                            ~~~~~~
    // error!
    // Argument of type '"blue"' is not assignable to parameter of type '"red" | "yellow" | "green" | undefined'.
    Cela fonctionne, mais c'est un peu gênant car D ne sera probablement utilisé nulle part ailleurs dans la signature de createStreetLight. Bien que ce ne soit pas mauvais dans ce cas, l'utilisation d'un paramètre de type une seule fois dans une signature est souvent une odeur de code.

    C'est pourquoi TypeScript 5.4 introduit un nouveau type utilitaire NoInfer<T>. Entourer un type de NoInfer<...> indique à TypeScript de ne pas creuser et de ne pas comparer les types internes pour trouver des candidats à l'inférence de type.

    En utilisant NoInfer, on peut réécrire createStreetLight comme suit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    function createStreetLight<C extends string>(colors: C[], defaultColor?: NoInfer<C>) {
        // ...
    }
     
    createStreetLight(["red", "yellow", "green"], "blue");
    //                                            ~~~~~~
    // error!
    // Argument of type '"blue"' is not assignable to parameter of type '"red" | "yellow" | "green" | undefined'.
    Exclure le type defaultColor de l'exploration pour l'inférence signifie que "blue" ne se retrouve jamais comme candidat à l'inférence, et que le vérificateur de type peut le rejeter.


    Object.groupBy et Map.groupBy

    TypeScript 5.4 ajoute des déclarations pour les nouvelles méthodes statiques JavaScript Object.groupBy et Map.groupBy.

    Object.groupBy prend un itérable et une fonction qui décide dans quel "groupe" chaque élément doit être placé. La fonction doit créer une "clé" pour chaque groupe distinct, et Object.groupBy utilise cette clé pour créer un objet où chaque clé correspond à un tableau contenant l'élément original.

    Voici donc le JavaScript suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    const array = [0, 1, 2, 3, 4, 5];
     
    const myObj = Object.groupBy(array, (num, index) => {
        return num % 2 === 0 ? "even": "odd";
    });
    équivaut en fait à écrire ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    const myObj = {
        even: [0, 2, 4],
        odd: [1, 3, 5],
    };
    Map.groupBy est similaire, mais produit une map au lieu d'un simple objet. Cela peut être plus souhaitable si vous avez besoin des garanties de Map, si vous travaillez avec des API qui attendent des Map, ou si vous avez besoin d'utiliser n'importe quel type de clé pour le regroupement - et pas seulement les clés qui peuvent être utilisées comme noms de propriétés en JavaScript.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    const myObj = Map.groupBy(array, (num, index) => {
        return num % 2 === 0 ? "even" : "odd";
    });
    et comme précédemment, vous auriez pu créer myObj d'une manière équivalente :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    const myObj = new Map();
     
    myObj.set("even", [0, 2, 4]);
    myObj.set("odd", [1, 3, 5]);
    Notez que dans l'exemple ci-dessus d'Object.groupBy, l'objet produit utilise toutes les propriétés optionnelles.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    interface EvenOdds {
        even?: number[];
        odd?: number[];
    }
     
    const myObj: EvenOdds = Object.groupBy(...);
     
    myObj.even;
    //    ~~~~
    // Error to access this under 'strictNullChecks'.
    Ceci est dû au fait qu'il n'y a aucun moyen de garantir de manière générale que toutes les clés ont été produites par groupBy.

    Notez également que ces méthodes ne sont accessibles qu'en configurant target à esnext ou en ajustant les paramètres de lib. Microsoft espère qu'elles seront éventuellement disponibles sous une cible stable es2024.


    Support des appels require() dans --moduleResolution bundler et --module preserve

    TypeScript dispose d'une option moduleResolution appelée bundler qui est censée modéliser la façon dont les bundlers modernes déterminent à quel fichier un chemin d'importation fait référence. L'une des limitations de cette option est qu'elle doit être associée à --module esnext, ce qui rend impossible l'utilisation de la syntaxe import ... = require(...).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    // previously errored
    import myModule = require("module/path");
    Cela peut sembler anodin si vous prévoyez d'écrire des importations ECMAScript standard, mais il y a une différence lorsque vous utilisez un package avec des exportations conditionnelles.

    Dans TypeScript 5.4, require() peut désormais être utilisé pour définir le paramètre de module avec une nouvelle option appelée preserve.

    Entre --module preserve et --moduleResolution bundler, les deux modélisent plus précisément ce que les bundlers et les runtimes comme Bun autoriseront, et comment ils effectueront les recherches de modules. En fait, en utilisant --module preserve, l'option bundler sera implicitement définie pour --moduleResolution (avec --esModuleInterop et --resolveJsonModule).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    {
        "compilerOptions": {
            "module": "preserve",
            // ^ also implies:
            // "moduleResolution": "bundler",
            // "esModuleInterop": true,
            // "resolveJsonModule": true,
     
            // ...
        }
    }
    Sous --module preserve, un import ECMAScript sera toujours émis tel quel, et import ... = require(...) sera émis comme un appel à require() (bien qu'en pratique vous puissiez ne pas utiliser TypeScript pour emit, puisqu'il est probable que vous utilisiez un bundler pour votre code). Ceci est vrai quelle que soit l'extension du fichier contenant le code. Ainsi, la sortie de ce code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    import * as foo from "some-package/foo";
    import bar = require("some-package/bar");
    devrait ressembler à ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    import * as foo from "some-package/foo";
    var bar = require("some-package/bar");
    Cela signifie également que la syntaxe que vous choisissez détermine la manière dont les exportations conditionnelles sont prises en compte. Ainsi, dans l'exemple ci-dessus, si le package.json de some-package ressemble à ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    {
      "name": "some-package",
      "version": "0.0.1",
      "exports": {
        "./foo": {
            "import": "./esm/foo-from-import.mjs",
            "require": "./cjs/foo-from-require.cjs"
        },
        "./bar": {
            "import": "./esm/bar-from-import.mjs",
            "require": "./cjs/bar-from-require.cjs"
        }
      }
    }
    TypeScript résoudra ces chemins en [...]/some-package/esm/foo-from-import.mjs et [...]/some-package/cjs/bar-from-require.cjs.


    Attributs et assertions d'importation vérifiés

    Les attributs et assertions d'importation sont désormais vérifiés par rapport au type global ImportAttributes. Cela signifie que les moteurs d'exécution peuvent maintenant décrire plus précisément les attributs d'importation.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // In some global file.
    interface ImportAttributes {
        type: "json";
    }
     
    // In some other module
    import * as ns from "foo" with { type: "not-json" };
    //                                     ~~~~~~~~~~
    // error!
    //
    // Type '{ type: "not-json"; }' is not assignable to type 'ImportAttributes'.
    //  Types of property 'type' are incompatible.
    //    Type '"not-json"' is not assignable to type '"json"'.

    Correction rapide pour l'ajout de paramètres manquants

    TypeScript dispose désormais d'une solution rapide pour ajouter un nouveau paramètre aux fonctions qui sont appelées avec trop d'arguments.

    Nom : 2.png
Affichages : 4437
Taille : 59,3 Ko

    Cela peut être utile pour faire passer un nouvel argument à travers plusieurs fonctions existantes, ce qui peut être encombrant aujourd'hui.


    Support de l'auto-importation pour les importations de sous-chemins

    Dans Node.js, package.json supporte une fonctionnalité appelée "subpath imports" via un champ appelé importss. Il s'agit d'un moyen de re-cartographier les chemins à l'intérieur d'un paquetage vers d'autres chemins de modules. Conceptuellement, c'est assez similaire au path-mapping, une fonctionnalité que certains bundlers et loaders de modules supportent (et que TypeScript supporte via une fonctionnalité appelée paths). La seule différence est que les importations de sous-chemins doivent toujours commencer par un #.

    La fonction d'auto-importation de TypeScript ne prenait pas en compte les chemins dans les importations, ce qui pouvait être frustrant. Au lieu de cela, les utilisateurs devaient définir manuellement les chemins dans leur fichier tsconfig.json. Cependant, les auto-imports de TypeScript supportent désormais les importations de sous-chemins !


    Changements à venir suite aux dépréciations de TypeScript 5.0

    TypeScript 5.0 a rendu obsolètes les options et comportements suivants :

    • charset
    • target: ES3
    • importsNotUsedAsValues
    • noImplicitUseStrict
    • noStrictGenericChecks
    • keyofStringsOnly
    • suppressExcessPropertyErrors
    • suppressImplicitAnyIndexErrors
    • out
    • preserveValueImports
    • prepend pour les projets références
    • newLine inmplicitemet spécifique à l'OS

    Pour continuer à les utiliser, les développeurs utilisant TypeScript 5.0 et d'autres versions plus récentes ont dû spécifier une nouvelle option appelée ignoreDeprecations avec la valeur "5.0".

    Cependant, TypScript 5.4 sera la dernière version dans laquelle elles continueront à fonctionner normalement. D'ici TypeScript 5.5 (probablement juin 2024), elles deviendront des erreurs difficiles à corriger, et le code qui les utilise devra être migré.


    Changements notables du comportement

    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.


    Changements dans 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.


    Contraintes de type conditionnelles plus précises

    Le code suivant n'autorise plus la deuxième déclaration de variable dans la fonction foo.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    type IsArray<T> = T extends any[] ? true : false;
     
    function foo<U extends object>(x: IsArray<U>) {
        let first: true = x;    // Error
        let second: false = x;  // Error, but previously wasn't
    }
    Auparavant, lorsque TypeScript vérifiait l'initialisateur pour second, il devait déterminer si IsArray<U> était assignable au type unitaire false. Bien que IsArray<U> ne soit pas compatible de manière évidente, TypeScript examine également la contrainte de ce type. Dans un type conditionnel comme T extends Foo ? TrueBranch : FalseBranch, où T est générique, le système de type regarderait la contrainte de T, la substituerait à T lui-même, et déciderait de la branche vraie ou fausse.

    Mais ce comportement était inexact car il était trop enthousiaste. Même si la contrainte de T n'est pas assignable à Foo, cela ne signifie pas qu'elle ne sera pas instanciée avec quelque chose qui l'est. Le comportement le plus correct est donc de produire un type union pour la contrainte du type conditionnel dans les cas où il n'est pas possible de prouver que T n'étend jamais ou toujours Foo.

    TypeScript 5.4 adopte ce comportement plus précis. Ce que cela signifie en pratique, c'est que vous pouvez commencer à trouver que certaines instances de type conditionnel ne sont plus compatibles avec leurs branches.


    Réduction plus agressive des intersections entre les variables de type et les types primitifs

    TypeScript réduit maintenant les intersections entre les variables de type et les primitives de manière plus agressive, en fonction de la façon dont la contrainte de la variable de type se superpose à ces primitives.

    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
    declare function intersect<T, U>(x: T, y: U): T & U;
     
    function foo<T extends "abc" | "def">(x: T, str: string, num: number) {
     
        // Was 'T & string', now is just 'T'
        let a = intersect(x, str);
     
        // Was 'T & number', now is just 'never'
        let b = intersect(x, num)
     
        // Was '(T & "abc") | (T & "def")', now is just 'T'
        let c = Math.random() < 0.5 ?
            intersect(x, "abc") :
            intersect(x, "def");
    }


    Amélioration de la vérification des chaînes de caractères avec interpolations

    TypeScript vérifie maintenant plus précisément si les chaînes de caractères sont assignables aux emplacements d'un modèle de chaîne de caractères.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    function a<T extends {id: string}>() {
        let x: `-${keyof T & string}`;
     
        // Used to error, now doesn't.
        x = "-id";
    }
    Ce comportement est plus souhaitable, mais peut causer des ruptures dans le code utilisant des constructions comme les types conditionnels, où ces changements de règles sont faciles à observer.


    Erreurs lorsque les importations de type seulement entrent en conflit avec les valeurs locales

    Auparavant, TypeScript autorisait le code suivant sous isolatedModules si l'importation vers Something ne faisait référence qu'à un type.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    import { Something } from "./some/path";
     
    let Something = 123;
    Cependant, il n'est pas sûr pour un compilateur à fichier unique de supposer qu'il est "sûr" d'abandonner l'importation, même si le code est garanti d'échouer à l'exécution. Dans TypeScript 5.4, ce code déclenchera une erreur comme la suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Import 'Something' conflicts with local value, so must be declared with a type-only import when 'isolatedModules' is enabled.
    La solution consiste soit à effectuer un renommage local, soit, comme l'indique l'erreur, à ajouter le modificateur de type à l'importation :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    import type { Something } from "./some/path";
     
    // or
     
    import { type Something } from "./some/path";


    Nouvelles restrictions d'assignabilité des enums

    Lorsque deux enums ont les mêmes noms déclarés et les mêmes noms de membres d'enum, ils étaient auparavant toujours considérés comme compatibles ; cependant, lorsque les valeurs étaient connues, TypeScript autorisait silencieusement qu'ils aient des valeurs différentes.

    TypeScript 5.4 renforce cette restriction en exigeant que les valeurs soient identiques lorsqu'elles sont connues.

    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
    namespace First {
        export enum SomeEnum {
            A = 0,
            B = 1,
        }
    }
     
    namespace Second {
        export enum SomeEnum {
            A = 0,
            B = 2,
        }
    }
     
    function foo(x: First.SomeEnum, y: Second.SomeEnum) {
        // Both used to be compatible - no longer the case,
        // TypeScript errors with something like:
        //
        //  Each declaration of 'SomeEnum.B' differs in its value, where '1' was expected but '2' was given.
        x = y;
        y = x;
    }
    De plus, il existe de nouvelles restrictions pour les cas où l'un des membres de l'énumération n'a pas de valeur statiquement connue. Dans ce cas, l'autre enum doit au moins être implicitement numérique (par exemple, il n'a pas d'initialisateur résolu statiquement), ou il est explicitement numérique (ce qui signifie que TypeScript pourrait résoudre la valeur en quelque chose de numérique). En pratique, cela signifie que les membres d'une énumération de chaînes de caractères ne sont jamais compatibles qu'avec d'autres énumérations de chaînes de caractères de même valeur.

    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
    namespace First {
        export declare enum SomeEnum {
            A,
            B,
        }
    }
     
    namespace Second {
        export declare enum SomeEnum {
            A,
            B = "some known string",
        }
    }
     
    function foo(x: First.SomeEnum, y: Second.SomeEnum) {
        // Both used to be compatible - no longer the case,
        // TypeScript errors with something like:
        //
        //  One value of 'SomeEnum.B' is the string '"some known string"', and the other is assumed to be an unknown numeric value.
        x = y;
        y = x;
    }


    Restrictions sur les noms des membres des enums

    TypeScript ne permet plus aux membres d'une énumération d'utiliser les noms Infinity, -Infinity ou NaN.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    // Errors on all of these:
    //
    //  An enum member cannot have a numeric name.
    enum E {
        Infinity = 0,
        "-Infinity" = 1,
        NaN = 2,
    }


    Meilleure préservation des types mappés sur les tuples avec n'importe quels éléments restants

    Auparavant, l'application d'un type mappé avec any dans un tuple créait un type d'élément any. Ceci n'est pas souhaitable et est maintenant corrigé.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Promise.all(["", ...([] as any)])
        .then((result) => {
            const head = result[0];       // 5.3: any, 5.4: string
            const tail = result.slice(1); // 5.3 any, 5.4: any[]
        });


    Changements dans l'émission

    Bien qu'il ne s'agisse pas d'un changement radical en soi, les développeurs peuvent avoir implicitement pris des dépendances sur les sorties d'émission de JavaScript ou de déclaration de TypeScript. Les changements suivants sont notables.

    • Préserver plus souvent les noms des paramètres de type lorsqu'ils sont masqués.
    • Déplacer les listes de paramètres complexes des fonctions asynchrones dans le corps du générateur de niveau inférieur.
    • Ne pas supprimer l'alias de liaison dans les déclarations de fonction
    • Les ImportAttributes devraient passer par les mêmes phases d'émission lorsqu'ils se trouvent dans un ImportTypeNode.


    Quelle est la suite ?

    Microsoft :

    Dans les mois à venir, nous travaillerons sur TypeScript 5.5, et vous pouvez consulter notre plan d'itération sur GitHub. Nos dates de publication sont publiques afin que vous, votre équipe et l'ensemble de la communauté TypeScript puissiez planifier en conséquence. Vous pouvez également essayer les versions nocturnes sur npm ou utiliser la dernière version de TypeScript et JavaScript dans Visual Studio Code.

    En attendant, TypeScript 5.4 reste la dernière et la meilleure version stable, et nous espérons qu'elle vous permettra de coder avec plaisir !
    Source : Daniel Rosenwasser et l'équipe TypeScript

    Et vous ?

    Quel est votre avis sur Typescript 5.4 ?

    Voir aussi :

    Microsoft annonce la disponibilité de la version candidate de TypeScript 5.4. Cette version corrige des bogues critiques et contient des changements notables de comportement

    TypeScript a 10 ans ! Joyeux anniversaire. À cette occasion, Microsoft fait le point. L'entreprise revient sur les doutes des premiers jours ainsi que sur l'évolution du langage
    Publication de communiqués de presse en informatique. 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.2 Beta.
    Par Nancy Rey dans le forum TypeScript
    Réponses: 2
    Dernier message: 10/08/2023, 10h46
  2. Microsoft annonce la disponibilité de TypeScript 2.9 RC
    Par Stéphane le calme dans le forum TypeScript
    Réponses: 5
    Dernier message: 05/06/2018, 10h23
  3. Réponses: 0
    Dernier message: 28/03/2018, 00h20
  4. Microsoft annonce la disponibilité de TypeScript 2.4
    Par Stéphane le calme dans le forum TypeScript
    Réponses: 1
    Dernier message: 28/06/2017, 07h38
  5. Réponses: 0
    Dernier message: 23/02/2017, 12h12

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