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 :

TypeScript 4.4 bêta est disponible et introduit l'indicateur --useUnknownInCatchVariable


Sujet :

TypeScript

  1. #1
    Chroniqueur Actualités

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Mars 2013
    Messages
    8 440
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Mars 2013
    Messages : 8 440
    Points : 197 499
    Points
    197 499
    Par défaut TypeScript 4.4 bêta est disponible et introduit l'indicateur --useUnknownInCatchVariable
    TypeScript 4.4 bêta est disponible et introduit l'indicateur --useUnknownInCatchVariable
    qui remplace any, le type par défaut des variables de clause catch, par unknown

    Analyse du flux de contrôle des conditions d'alias

    En JavaScript, nous devons souvent sonder une variable de différentes manières pour voir si elle a un type plus spécifique que nous pouvons utiliser. TypeScript comprend ces vérifications et les appelle des gardes de type. Au lieu d'avoir à convaincre TypeScript du type d'une variable chaque fois que nous l'utilisons, le vérificateur de type s'appuie sur ce qu'on appelle l'analyse de flux de contrôle pour déduire le type dans chaque construction de langage.

    Par exemple, nous pouvons écrire quelque chose comme :

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    function foo(arg: unknown) {
        if (typeof arg === "string") {
            // We know this is a string now.
            console.log(arg.toUpperCase());
        }
    }

    Dans cet exemple, nous avons vérifié si arg était un string. TypeScript a reconnu la vérification de typeof arg === "string", qu'il considérait comme une protection de type, et a pu déterminer que arg devrait être un string dans le corps du bloc if.

    Cependant, que se passe-t-il si nous déplaçons la condition vers une constante ?

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    function foo(arg: unknown) {
        const argIsString = typeof arg === "string";
        if (argIsString) {
            console.log(arg.toUpperCase());
            //              ~~~~~~~~~~~
            // Error! Property 'toUpperCase' does not exist on type 'unknown'.
        }
    }

    Dans les versions précédentes de TypeScript, cela aurait conduit à une erreur – même si argIsString avait reçu la valeur garde de type, TypeScript perdait simplement cette information. C'est dommage, car nous pourrions vouloir réutiliser la même vérification à plusieurs endroits. Pour contourner ce problème, les utilisateurs doivent souvent se répéter ou utiliser des assertions de type (casts).

    Dans TypeScript 4.4, ce n'est plus le cas. L'exemple ci-dessus fonctionne sans erreur ! Lorsque TypeScript voit que nous testons une valeur constante, il effectuera un peu de travail supplémentaire pour voir s'il contient une protection de type. Si cette protection de type opère sur un const, une propriété readonly ou un paramètre non modifié, alors TypeScript est capable de restreindre cette valeur de manière appropriée.

    Différentes sortes de conditions de garde de type sont préservées – pas seulement des vérifications typeof. Par exemple, les contrôles sur les syndicats discriminés fonctionnent comme un charme.

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    type Shape =
        | { kind: "circle", radius: number }
        | { kind: "square", sideLength: number };
     
    function area(shape: Shape): number {
        const isCircle = shape.kind === "circle";
        if (isCircle) {
            // We know we have a circle here!
            return Math.PI * shape.radius ** 2;
        }
        else {
            // We know we're left with a square here!
            return shape.sideLength ** 2;
        }
    }

    Comme autre exemple, voici une fonction qui vérifie si deux de ses entrées ont un contenu.

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function doSomeChecks(
        inputA: string | undefined,
        inputB: string | undefined,
        shouldDoExtraWork: boolean,
    ) {
        let mustDoWork = inputA && inputB && shouldDoExtraWork;
        if (mustDoWork) {
            // Can access 'string' properties on both 'inputA' and 'inputB'!
            const upperA = inputA.toUpperCase();
            const upperB = inputB.toUpperCase();
            // ...
        }
    }

    TypeScript peut comprendre que inputA et inputB sont tous deux présents si mustDoWork est true. Cela signifie que nous n'avons pas à écrire une assertion non nulle comme inputA! pour convaincre TypeScript que inputA est undefined.

    Une caractéristique intéressante ici est que cette analyse fonctionne de manière transitive. Si nous avons une constante affectée à une condition qui contient plus de constantes et que ces constantes sont chacune affectées à des gardes de type, alors TypeScript peut propager les conditions plus tard.

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function f(x: string | number | boolean) {
        const isString = typeof x === "string";
        const isNumber = typeof x === "number";
        const isStringOrNumber = isString || isNumber;
        if (isStringOrNumber) {
            x;  // Type of 'x' is 'string | number'.
        }
        else {
            x;  // Type of 'x' is 'boolean'.
        }
    }

    Notez qu'il y a une limite - TypeScript ne va pas arbitrairement en profondeur lors de la vérification de ces conditions, mais son analyse est suffisamment approfondie pour la plupart des vérifications.

    Cette fonctionnalité devrait permettre à beaucoup de code JavaScript intuitif de «*fonctionner*» dans TypeScript sans que cela ne vous gêne.

    Nom : type.png
Affichages : 19729
Taille : 2,5 Ko

    Signatures d'index Template String Pattern et symbol

    TypeScript nous permet de décrire des objets où chaque propriété doit avoir un certain type à l'aide de signatures d'index. Cela nous permet d'utiliser ces objets comme des types de type dictionnaire, où nous pouvons utiliser des clés de chaîne pour les indexer avec des crochets.

    Par exemple, nous pouvons écrire un type avec une signature d'index qui accepte les clés de chaîne et correspond à des valeurs booléennes. Si nous essayons d'attribuer autre chose qu'une valeur booléenne, nous obtiendrons une erreur.

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    interface BooleanDictionary {
        [key: string]: boolean;
    }
     
    declare let myDict: BooleanDictionary;
     
    // Valid to assign boolean values
    myDict["foo"] = true;
    myDict["bar"] = false;
     
    // Error, "oops" isn't a boolean
    myDict["baz"] = "oops";

    Alors qu'une Map peut être une meilleure structure de données ici (en particulier, une Map<string, boolean>), les objets JavaScript sont souvent plus pratiques à utiliser ou se trouvent simplement être ce avec quoi on nous donne de travailler.

    De même, Array<T> définit déjà une signature d'index numérique qui nous permet d'insérer/récupérer des valeurs de type T.

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // This is part of TypeScript's definition of the built-in Array type.
    interface Array<T> {
        [index: number]: T;
     
        // ...
    }
     
    let arr = new Array<string>();
     
    // Valid
    arr[0] = "hello!";
     
    // Error, expecting a 'string' value here
    arr[1] = 123;

    Les signatures d'index sont très utiles pour exprimer beaucoup de code à l'état brut ; cependant, jusqu'à présent, ils étaient limités aux clés string et number (et les signatures d'index de chaîne ont une bizarrerie intentionnelle où elles peuvent accepter les clés de nombre, car elles seront de toute façon contraintes à des chaînes). Cela signifie que TypeScript n'autorisait pas l'indexation des objets avec des clés symbol. TypeScript ne pouvait pas non plus modéliser une signature d'index d'un sous-ensemble de clés de chaîne - par exemple, une signature d'index qui décrit uniquement les propriétés dont les noms commencent par les textes data-.

    TypeScript 4.4 résout ces limitations et autorise les signatures d'index pour les symboles et les modèles de chaînes de modèles.

    Par exemple, TypeScript nous permet désormais de déclarer un type dont la clé peut être sur des symbol arbitraires.

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    interface Colors {
        [sym: symbol]: number;
    }
     
    const red = Symbol("red");
    const green = Symbol("green");
    const blue = Symbol("blue");
     
    let colors: Colors = {};
     
    colors[red] = 255;          // Assignment of a number is allowed
    let redVal = colors[red];   // 'redVal' has the type 'number'
     
    colors[blue] = "da ba dee"; // Error: Type 'string' is not assignable to type 'number'.

    De même, nous pouvons écrire une signature d'index avec le type de modèle de chaîne de modèle. Une utilisation de ceci pourrait être d'exempter les propriétés commençant par les données de la vérification des propriétés en excès de TypeScript. Lorsque nous passons un objet littéral à quelque chose avec un type attendu, TypeScript recherchera les propriétés excédentaires qui n'ont pas été déclarées dans le type attendu.

    Code TypeScript : 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
    interface Options {
        width?: number;
        height?: number;
    }
     
    let a: Options = {
        width: 100,
        height: 100,
        "data-blah": true, // Error! 'data-blah' wasn't declared in 'Options'.
    };
     
    interface OptionsWithDataProps extends Options {
        // Permit any property starting with 'data-'.
        [optName: `data-${string}`]: unknown;
    }
     
    let b: OptionsWithDataProps = {
        width: 100,
        height: 100,
        "data-blah": true,       // Works!
     
        "unknown-property": true,  // Error! 'unknown-property' wasn't declared in 'OptionsWithDataProps'.
    };

    Une dernière remarque sur les signatures d'index est qu'elles autorisent désormais les types d'union, tant qu'il s'agit d'une union de types primitifs de domaine infini, en particulier*:
    • string
    • number
    • symbol
    • template de chaîne de modèle (par exemple `hello-${string}`)

    Une signature d'index dont l'argument est une union de ces types se détendra en plusieurs signatures d'index différentes.
    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    interface Data {
        [optName: string | symbol]: any;
    }
     
    // Equivalent to
     
    interface Data {
        [optName: string]: any;
        [optName: symbol]: any;
    }

    Par défaut, le type unknown dans les variables de capture (--useUnknownInCatchVariables)

    En JavaScript, tout type de valeur peut être lancé avec throw et capturé dans une clause catch. Pour cette raison, TypeScript a historiquement typé les variables de clause catch comme any et n'autorisait aucune autre annotation de type*:

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    try {
        // Who knows what this might throw...
        executeSomeThirdPartyCode();
    }
    catch (err) { // err: any
        console.error(err.message); // Allowed, because 'any'
        err.thisWillProbablyFail(); // Allowed, because 'any' :(
    }

    Une fois que TypeScript a ajouté le type unknown, il est devenu clair qu'unknown était un meilleur choix que any dans la clause catch pour les utilisateurs qui souhaitent le plus haut degré d'exactitude et de sécurité de type, car il se rétrécit mieux et nous oblige à tester par rapport à des valeurs arbitraires. Finalement, TypeScript 4.0 a permis aux utilisateurs de spécifier une annotation de type explicite [C]unknown[/] (ou catch) sur chaque variable de clause catch afin que nous puissions opter pour des types plus stricts au cas par cas*; cependant, pour certains, spécifier manuellement : unknown sur chaque clause catch était une corvée.

    C'est pourquoi TypeScript 4.4 introduit un nouvel indicateur appelé --useUnknownInCatchVariables. Cet indicateur modifie le type par défaut des variables de clause catch de any à unknown.

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    try {
        executeSomeThirdPartyCode();
    }
    catch (err) { // err: unknown
     
        // Error! Property 'message' does not exist on type 'unknown'.
        console.error(err.message);
     
        // Works! We can narrow 'err' from 'unknown' to 'Error'.
        if (err instanceof Error) {
            console.error(err.message);
        }
    }

    Source : Microsoft

    Voir aussi :

    TypeScript 4.3 est disponible et apporte le mot-clé override pour qu'un dev puisse indiquer clairement s'il avait l'intention d'ajouter une nouvelle méthode ou de remplacer une méthode existante
    Le créateur de Python, Guido van Rossum, dit ce qu'il pense de Rust, Go, Julia et TypeScript et relève des similitudes entre ces langages et Python
    L'équipe Angular de Google annonce la version 12 d'Angular, le framework open source basé sur TypeScript, elle améliore le service de langue basé sur Ivy et apporte de nouvelles fonctionnalités
    Contribuez au club : Corrections, suggestions, critiques, ... : Contactez le service news et Rédigez des actualités

  2. #2
    Chroniqueur Actualités

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Mars 2013
    Messages
    8 440
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Mars 2013
    Messages : 8 440
    Points : 197 499
    Points
    197 499
    Par défaut TypeScript 4.4 RC est disponible. L'équipe n'attend aucun changement entre cette version et celle en GA
    TypeScript 4.4 RC est disponible. L'équipe n'attend aucun changement entre cette version et celle en disponibilité générale,
    en dehors des corrections des bogues critiques

    « Aujourd'hui, nous sommes ravis d'annoncer notre Release Candidate (RC) de TypeScript 4.4 ! Entre maintenant et la version stable de TypeScript 4.4, nous n'attendons aucun autre changement en dehors des corrections de bogues critiques ».

    Types de propriétés facultatifs exacts (--exactOptionalPropertyTypes)

    En JavaScript, la lecture d'une propriété manquante sur un objet produit la valeur undefined. Il est également possible d'avoir une propriété réelle avec la valeur undefined. Beaucoup de code en JavaScript a tendance à traiter ces situations de la même manière, et donc initialement, TypeScript a simplement interprété chaque propriété facultative comme si un utilisateur avait écrit undefined dans le type. Par exemple,

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    interface Person {
        name: string,
        age?: number;
    }

    était considérée comme équivalente à

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    interface Person {
        name: string,
        age?: number | undefined;
    }

    Cela signifiait qu'un utilisateur pouvait explicitement écrire undefined à la place de age.

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    const p: Person = {
        name: "Daniel",
        age: undefined, // This is okay by default.
    };

    Ainsi, par défaut, TypeScript ne fait pas la distinction entre une propriété actuelle avec la valeur undefined et une propriété manquante. Bien que cela fonctionne la plupart du temps, tout le code en JavaScript ne fait pas les mêmes hypothèses. Les fonctions et opérateurs tels que Object.assign, Object.keys, ({ ...obj }) et les boucles for–in se comportent différemment selon qu'une propriété existe ou non sur un objet. Dans le cas de notre exemple Person, cela pourrait potentiellement conduire à des erreurs d'exécution si la propriété age était observée dans un contexte où sa présence était importante.

    Dans TypeScript 4.4, le nouvel indicateur --exactOptionalPropertyTypes spécifie que les types de propriétés facultatifs doivent être interprétés exactement comme écrits, ce qui signifie que | undefined n'est pas ajouté au type*:

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    // With 'exactOptionalPropertyTypes' on:
    const p: Person = {
        name: "Daniel",
        age: undefined, // Error! undefined isn't a number
    };

    Ce drapeau ne fait pas partie de la famille --strict et doit être activé explicitement si vous souhaitez ce comportement. Cela nécessite également que --strictNullChecks soit également activé. L'équipe va mettre à jour DefinitelyTyped et d'autres définitions pour essayer de rendre la transition aussi simple que possible, mais vous pouvez rencontrer des frictions avec cela selon la façon dont votre code est structuré.

    Blocs static dans les classes

    TypeScript 4.4 prend en charge les blocs statiques dans les classes, une fonctionnalité ECMAScript à venir qui peut vous aider à écrire un code d'initialisation plus complexe pour les membres statiques.

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class Foo {
        static count = 0;
     
        // This is a static block:
        static {
            if (someCondition()) {
                count++;
            }
        }
    }

    Ces blocs statiques vous permettent d'écrire une séquence d'instructions avec leur propre portée pouvant accéder aux champs privés de la classe conteneur. Cela signifie que nous pouvons écrire du code d'initialisation avec toutes les capacités d'écriture d'instructions, aucune fuite de variables et un accès complet aux composants internes de notre classe.

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class Foo {
        static #count = 0;
     
        get count() {
            return this.#count;
        }
     
        static {
            try {
                const lastInstances = loadLastInstances();
                count += lastInstances.length;
            }
            catch {}
        }
    }

    Sans blocs static, l'écriture du code ci-dessus était possible, mais impliquait souvent plusieurs types de piratages différents qui devaient être compromis d'une manière ou d'une autre. Notez qu'une classe peut avoir plusieurs blocs static et qu'ils sont exécutés dans le même ordre dans lequel ils sont écrits.

    Code TypeScript : 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
    // Prints:
    //    1
    //    2
    //    3
    class Foo {
        static prop = 1
        static {
            console.log(1);
        }
        static {
            console.log(2);
        }
        static {
            console.log(3);
        }
    }

    Nom : type.png
Affichages : 11152
Taille : 2,5 Ko

    Analyse du flux de contrôle des conditions d'alias

    En JavaScript, nous devons souvent sonder une variable de différentes manières pour voir si elle a un type plus spécifique que nous pouvons utiliser. TypeScript comprend ces vérifications et les appelle des gardes de type. Au lieu d'avoir à convaincre TypeScript du type d'une variable chaque fois que nous l'utilisons, le vérificateur de type s'appuie sur ce qu'on appelle l'analyse de flux de contrôle pour déduire le type dans chaque construction de langage.

    Par exemple, nous pouvons écrire quelque chose comme :

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    function foo(arg: unknown) {
        if (typeof arg === "string") {
            // We know this is a string now.
            console.log(arg.toUpperCase());
        }
    }

    Dans cet exemple, nous avons vérifié si arg était un string. TypeScript a reconnu la vérification de typeof arg === "string", qu'il considérait comme une protection de type, et a pu déterminer que arg devrait être un string dans le corps du bloc if.

    Cependant, que se passe-t-il si nous déplaçons la condition vers une constante ?

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    function foo(arg: unknown) {
        const argIsString = typeof arg === "string";
        if (argIsString) {
            console.log(arg.toUpperCase());
            //              ~~~~~~~~~~~
            // Error! Property 'toUpperCase' does not exist on type 'unknown'.
        }
    }

    Dans les versions précédentes de TypeScript, cela aurait conduit à une erreur – même si argIsString avait reçu la valeur garde de type, TypeScript perdait simplement cette information. C'est dommage, car nous pourrions vouloir réutiliser la même vérification à plusieurs endroits. Pour contourner ce problème, les utilisateurs doivent souvent se répéter ou utiliser des assertions de type (casts).

    Dans TypeScript 4.4, ce n'est plus le cas. L'exemple ci-dessus fonctionne sans erreur ! Lorsque TypeScript voit que nous testons une valeur constante, il effectuera un peu de travail supplémentaire pour voir s'il contient une protection de type. Si cette protection de type opère sur un const, une propriété readonly ou un paramètre non modifié, alors TypeScript est capable de restreindre cette valeur de manière appropriée.

    Différentes sortes de conditions de garde de type sont préservées – pas seulement des vérifications typeof. Par exemple, les contrôles sur les syndicats discriminés fonctionnent comme un charme.

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    type Shape =
        | { kind: "circle", radius: number }
        | { kind: "square", sideLength: number };
     
    function area(shape: Shape): number {
        const isCircle = shape.kind === "circle";
        if (isCircle) {
            // We know we have a circle here!
            return Math.PI * shape.radius ** 2;
        }
        else {
            // We know we're left with a square here!
            return shape.sideLength ** 2;
        }
    }

    Comme autre exemple, voici une fonction qui vérifie si deux de ses entrées ont un contenu.

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function doSomeChecks(
        inputA: string | undefined,
        inputB: string | undefined,
        shouldDoExtraWork: boolean,
    ) {
        let mustDoWork = inputA && inputB && shouldDoExtraWork;
        if (mustDoWork) {
            // Can access 'string' properties on both 'inputA' and 'inputB'!
            const upperA = inputA.toUpperCase();
            const upperB = inputB.toUpperCase();
            // ...
        }
    }

    TypeScript peut comprendre que inputA et inputB sont tous deux présents si mustDoWork est true. Cela signifie que nous n'avons pas à écrire une assertion non nulle comme inputA! pour convaincre TypeScript que inputA est undefined.

    Une caractéristique intéressante ici est que cette analyse fonctionne de manière transitive. Si nous avons une constante affectée à une condition qui contient plus de constantes et que ces constantes sont chacune affectées à des gardes de type, alors TypeScript peut propager les conditions plus tard.

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function f(x: string | number | boolean) {
        const isString = typeof x === "string";
        const isNumber = typeof x === "number";
        const isStringOrNumber = isString || isNumber;
        if (isStringOrNumber) {
            x;  // Type of 'x' is 'string | number'.
        }
        else {
            x;  // Type of 'x' is 'boolean'.
        }
    }

    Notez qu'il y a une limite - TypeScript ne va pas arbitrairement en profondeur lors de la vérification de ces conditions, mais son analyse est suffisamment approfondie pour la plupart des vérifications.

    Cette fonctionnalité devrait permettre à beaucoup de code JavaScript intuitif de « fonctionner » dans TypeScript sans que cela ne vous gêne.

    Signatures d'index Template String Pattern et symbol

    TypeScript nous permet de décrire des objets où chaque propriété doit avoir un certain type à l'aide de signatures d'index. Cela nous permet d'utiliser ces objets comme des types de type dictionnaire, où nous pouvons utiliser des clés de chaîne pour les indexer avec des crochets.

    Par exemple, nous pouvons écrire un type avec une signature d'index qui accepte les clés de chaîne et correspond à des valeurs booléennes. Si nous essayons d'attribuer autre chose qu'une valeur booléenne, nous obtiendrons une erreur.

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    interface BooleanDictionary {
        [key: string]: boolean;
    }
     
    declare let myDict: BooleanDictionary;
     
    // Valid to assign boolean values
    myDict["foo"] = true;
    myDict["bar"] = false;
     
    // Error, "oops" isn't a boolean
    myDict["baz"] = "oops";

    Alors qu'une Map peut être une meilleure structure de données ici (en particulier, une Map<string, boolean>), les objets JavaScript sont souvent plus pratiques à utiliser ou se trouvent simplement être ce avec quoi on nous donne de travailler.

    De même, Array<T> définit déjà une signature d'index numérique qui nous permet d'insérer/récupérer des valeurs de type T.

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // This is part of TypeScript's definition of the built-in Array type.
    interface Array<T> {
        [index: number]: T;
     
        // ...
    }
     
    let arr = new Array<string>();
     
    // Valid
    arr[0] = "hello!";
     
    // Error, expecting a 'string' value here
    arr[1] = 123;

    Les signatures d'index sont très utiles pour exprimer beaucoup de code à l'état brut ; cependant, jusqu'à présent, ils étaient limités aux clés string et number (et les signatures d'index de chaîne ont une bizarrerie intentionnelle où elles peuvent accepter les clés de nombre, car elles seront de toute façon contraintes à des chaînes). Cela signifie que TypeScript n'autorisait pas l'indexation des objets avec des clés symbol. TypeScript ne pouvait pas non plus modéliser une signature d'index d'un sous-ensemble de clés de chaîne - par exemple, une signature d'index qui décrit uniquement les propriétés dont les noms commencent par les textes data-.

    TypeScript 4.4 résout ces limitations et autorise les signatures d'index pour les symboles et les modèles de chaînes de modèles.

    Par exemple, TypeScript nous permet désormais de déclarer un type dont la clé peut être sur des symbol arbitraires.

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    interface Colors {
        [sym: symbol]: number;
    }
     
    const red = Symbol("red");
    const green = Symbol("green");
    const blue = Symbol("blue");
     
    let colors: Colors = {};
     
    colors[red] = 255;          // Assignment of a number is allowed
    let redVal = colors[red];   // 'redVal' has the type 'number'
     
    colors[blue] = "da ba dee"; // Error: Type 'string' is not assignable to type 'number'.

    De même, nous pouvons écrire une signature d'index avec le type de modèle de chaîne de modèle. Une utilisation de ceci pourrait être d'exempter les propriétés commençant par les données de la vérification des propriétés en excès de TypeScript. Lorsque nous passons un objet littéral à quelque chose avec un type attendu, TypeScript recherchera les propriétés excédentaires qui n'ont pas été déclarées dans le type attendu.

    Code TypeScript : 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
    interface Options {
        width?: number;
        height?: number;
    }
     
    let a: Options = {
        width: 100,
        height: 100,
        "data-blah": true, // Error! 'data-blah' wasn't declared in 'Options'.
    };
     
    interface OptionsWithDataProps extends Options {
        // Permit any property starting with 'data-'.
        [optName: `data-${string}`]: unknown;
    }
     
    let b: OptionsWithDataProps = {
        width: 100,
        height: 100,
        "data-blah": true,       // Works!
     
        "unknown-property": true,  // Error! 'unknown-property' wasn't declared in 'OptionsWithDataProps'.
    };

    Une dernière remarque sur les signatures d'index est qu'elles autorisent désormais les types d'union, tant qu'il s'agit d'une union de types primitifs de domaine infini, en particulier*:
    • string
    • number
    • symbol
    • template de chaîne de modèle (par exemple `hello-${string}`)

    Une signature d'index dont l'argument est une union de ces types se détendra en plusieurs signatures d'index différentes.
    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    interface Data {
        [optName: string | symbol]: any;
    }
     
    // Equivalent to
     
    interface Data {
        [optName: string]: any;
        [optName: symbol]: any;
    }

    Par défaut, le type unknown dans les variables de capture (--useUnknownInCatchVariables)

    En JavaScript, tout type de valeur peut être lancé avec throw et capturé dans une clause catch. Pour cette raison, TypeScript a historiquement typé les variables de clause catch comme any et n'autorisait aucune autre annotation de type*:

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    try {
        // Who knows what this might throw...
        executeSomeThirdPartyCode();
    }
    catch (err) { // err: any
        console.error(err.message); // Allowed, because 'any'
        err.thisWillProbablyFail(); // Allowed, because 'any' :(
    }

    Une fois que TypeScript a ajouté le type unknown, il est devenu clair qu'unknown était un meilleur choix que any dans la clause catch pour les utilisateurs qui souhaitent le plus haut degré d'exactitude et de sécurité de type, car il se rétrécit mieux et nous oblige à tester par rapport à des valeurs arbitraires. Finalement, TypeScript 4.0 a permis aux utilisateurs de spécifier une annotation de type explicite [C]unknown[/] (ou catch) sur chaque variable de clause catch afin que nous puissions opter pour des types plus stricts au cas par cas*; cependant, pour certains, spécifier manuellement : unknown sur chaque clause catch était une corvée.

    C'est pourquoi TypeScript 4.4 introduit un nouvel indicateur appelé --useUnknownInCatchVariables. Cet indicateur modifie le type par défaut des variables de clause catch de any à unknown.

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    try {
        executeSomeThirdPartyCode();
    }
    catch (err) { // err: unknown
     
        // Error! Property 'message' does not exist on type 'unknown'.
        console.error(err.message);
     
        // Works! We can narrow 'err' from 'unknown' to 'Error'.
        if (err instanceof Error) {
            console.error(err.message);
        }
    }

    Source : blog TypeScript
    Contribuez au club : Corrections, suggestions, critiques, ... : Contactez le service news et Rédigez des actualités

Discussions similaires

  1. La version stable de TypeScript 3.7.0 est disponible
    Par Patrick Ruiz dans le forum TypeScript
    Réponses: 11
    Dernier message: 09/11/2019, 20h53
  2. PostgreSQL 12 est disponible et introduit les « colonnes calculées »
    Par Stéphane le calme dans le forum PostgreSQL
    Réponses: 3
    Dernier message: 09/10/2019, 10h51
  3. Réponses: 5
    Dernier message: 27/02/2016, 21h45
  4. Réponses: 0
    Dernier message: 16/06/2015, 08h01
  5. PureBasic 4.50 bêta est disponible
    Par comtois dans le forum PureBasic
    Réponses: 5
    Dernier message: 09/05/2010, 13h15

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