1. #1
    Rédacteur/Modérateur

    Avatar de yahiko
    Homme Profil pro
    Ninja
    Inscrit en
    juillet 2013
    Messages
    1 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ninja

    Informations forums :
    Inscription : juillet 2013
    Messages : 1 153
    Points : 6 568
    Points
    6 568
    Billets dans le blog
    43

    Par défaut TypeScript 3.0 est disponible en version stable

    La Release Candidate de TypeScript 3.0 vient de sortir
    avec une gestion de projets améliorée


    L'équipe TypeScript de Microsoft a publié le 12 juillet une version majeure du désormais fameux surensemble typé de JavaScript en Release Candidate. Pour l'installer, rien de plus simple :

    npm install -g typescript@rc

    Cette version est également disponible sous la forme de plugin pour Visual Studio 2017.

    Référencement de projets TypeScript externes

    Il est assez courant d'avoir plusieurs étapes de génération (build) différentes pour une bibliothèque ou une application. Un projet peut avoir un répertoire src et un répertoire test. On peut avoir son code front-end dans un dossier appelé client, son code back-end Node.js dans un dossier appelé server, chacun important du code à partir d'un dossier shared. Une base de code peut aussi être structurée sous la forme d'un « monorepo » avec beaucoup de projets qui dépendent les uns des autres de manière non triviale.

    L'une des principales fonctionnalités de TypeScript 3.0 est appelée « références de projet », et vise à faciliter le travail avec ces scénarios.

    Les références de projet permettent aux projets TypeScript de dépendre d'autres projets TypeScript, notamment en permettant aux fichiers tsconfig.json de référencer d'autres fichiers tsconfig.json. La spécification de ces dépendances facilite la division de votre code en projets plus petits, car il donne à TypeScript (et aux outils qui l'entourent) un moyen de comprendre l'ordre de génération et la structure de sortie. Cela permet des choses comme des générations plus rapides qui fonctionnent de manière incrémentale, ou encore une navigation transparente, la modification et le refactoring entre projets. Puisque la version 3.0 pose les fondations et expose les API, n'importe quel outil de génération (les IDE notamment) devrait pouvoir fournir cette fonctionnalité.

    A quoi cela ressemble-t-il ?

    Pour illustrer rapidement cette nouvelle possibilité, voici à quoi ressemble un tsconfig.json avec des références de projet:

    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
    // ./src/bar/tsconfig.json
    {
        "compilerOptions": {
            // Needed for project references.
            "composite": true,
            "declaration": true,
     
            // Other options...
            "outDir": "../../lib/bar",
            "strict": true, "module": "esnext", "moduleResolution": "node",
        },
        "references": [
            { "path": "../foo" }
        ]
    }
    Il y a deux nouveaux champs à noter ici : composite et references.

    Le champ references spécifie simplement les autres fichiers tsconfig.json (ou les dossiers qui les contiennent directement). Chaque référence n'est actuellement qu'un objet ne contenant qu'un champ path, et permet à TypeScript de savoir que la génération du projet actuel nécessite une génération préalable des autres projets référencés.

    Peut-être tout aussi important est le champ composite. Ce champ garantit que certaines options sont activées afin que ce projet puisse être référencé et généré de façon incrémentale pour tout projet qui en dépend. Être capable de reconstruire intelligemment et de façon incrémentale est important, puisque la vitesse de génération est l'une des principales raisons pour lesquelles nous pouvons avoir envie de décomposer un projet. Par exemple, si le projet front-end dépend de shared, et shared dépend de core, les API sur les références de projet peuvent non seulement détecter un changement dans core, mais aussi régénérer shared seulement si les types (i.e. les fichiers .d.ts) produit par core ont changé. Cela signifie qu'un changement de core ne nous force pas complètement à régénérer l'ensemble du projet. Pour cette raison, définir le paramètre composite oblige le champ declaration à être défini en même temps.

    Mode --build

    TypeScript 3.0 fournit un ensemble d'API pour les références de projet afin que d'autres outils puissent fournir rapidement cette génération incrémentale. A titre d'exemple, gulp-typescript le supporte déjà. Les références de projet devraient donc pouvoir être supportées par votre orchestrateur de build dans le futur.

    Cependant, pour de nombreuses applications et bibliothèques simples, il est préférable de ne pas avoir besoin d'outils externes. C'est pourquoi tsc est désormais livré avec une nouvelle option --build.

    tsc --build (raccourci, tsc -b) prend un ensemble de projets et les génère avec leurs dépendances. Lors de l'utilisation de ce nouveau mode de génération, l'option --build doit être définie en premier et peut être associée à certaines autres options :

    --verbose : affiche toutes les étapes nécessaires à la génération
    --dry : effectue une génération sans émettre de fichiers (ceci est utile avec --verbose)
    --clean : tente de supprimer les fichiers de sortie en fonction des entrées
    --force : force une regénération complète non incrémentale pour un projet

    Organisation de la structure en sortie

    Un avantage subtil, mais incroyablement utile des références de projet, est la possibilité de mapper de façon logique votre code source en entrée à ses sorties.

    Si vous avez déjà essayé de partager du code TypeScript entre les parties client et serveur de votre application, vous avez peut-être rencontré des problèmes d'organisation de la structure en sortie.

    Par exemple, si client/index.ts et server/index.ts font tous deux référence à shared/index.ts pour les projets suivants :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    src
    +-- client
    |   +-- index.ts
    |   +-- tsconfig.json
    +-- server
    |   +-- index.ts
    |   +-- tsconfig.json
    +-- shared
        +-- index.ts
    ... alors, en essayant de générer client et server, on aboutit à cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    lib
    +-- client
    |   +-- client
    |   |   +-- index.js
    |   +-- shared
    |       +-- index.js
    +-- server
        +-- server
        |   +-- index.js
        +-- shared
            +-- index.js
    au lieu de cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    lib
    +-- client
    |   +-- index.js
    +-- shared
    |   +-- index.js
    +-- server
        +-- index.js
    Notez que nous nous sommes retrouvés avec une copie de shared à la fois dans client et dans server. Aussi, nous avons passé un temps inutile à générer shared et avons introduit un niveau d'imbrication indésirable dans lib/client/client et lib/server/server.

    Le problème est que TypeScript lit les les fichiers .ts de manière « gourmande » (greedy) et essaie de les inclure dans une compilation donnée. Dans l'idéal, TypeScript devrait comprendre que ces fichiers n'ont pas besoin d'être générés dans la même compilation, et devrait plutôt passer directement aux fichiers .d.ts pour récupérer les informations de type.

    La création d'un fichier tsconfig.json pour partager et utiliser des références de projet fait exactement cela. Il signale à TypeScript que
    1. shared devrait être généré indépendamment, et que
    2. lors de l'importation depuis ../shared, nous devrions rechercher les fichiers .d.ts dans son répertoire de sortie.

    Cela évite de déclencher une double génération, et évite également de consommer accidentellement tout le contenu de shared.

    Travaux à venir

    Pour mieux comprendre les références de projets et savoir comment les utiliser, vous pouvez consulter le suivi des problèmes. Dans un avenir proche, une documentation plus détaillée sera publiée sur les références de projets et le mode --build.

    Extraction et expansion de listes de paramètres avec des n-uplets

    JavaScript peut nous laisser à penser que les listes de paramètres sont des valeurs de première classe -- soit en utilisant arguments ou ...args.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    function call(fn, ...args) {
        return fn(...args);
    }
    Notez ici que call fonctionne sur les fonctions ayant un nombre de paramètres quelconques. Contrairement à d'autres langages, nous n'avons pas besoin de définir de call1, call2, call3 comme suit:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function call1(fn, param1) {
        return fn(param1);
    }
     
    function call2(fn, param1, param2) {
        return fn(param1, param2);
    }
     
    function call3(fn, param1, param2, param3) {
        return fn(param1, param2, param3);
    }
    Cependant, jusqu'à présent, il n'y avait pas de manière très élégante pour typer statiquement en TypeScript sans avoir à déclarer un nombre fini de surcharges (overloads) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    // TODO (billg): 4 overloads should *probably* be enough for anybody?
    function call<T1, T2, T3, T4, R>(fn: (param1: T1, param2: T2, param3: T3, param4: T4) => R, param1: T1, param2: T2, param3: T3, param4: T4);
    function call<T1, T2, T3, R>(fn: (param1: T1, param2: T2, param3: T3) => R, param1: T1, param2: T2, param3: T3);
    function call<T1, T2, R>(fn: (param1: T1, param2: T2) => R, param1: T1, param2: T2);
    function call<T1, R>(fn: (param1: T1) => R, param1: T1): R;
    function call(fn: (...args: any[]) => any, ...args: any[]) {
        fn(...args);
    }
    Avouons que ce n'est pas terrible, car cela implique autant de surcharges que de besoins différents en termes de nombre de paramètres.

    TypeScript 3.0 permet de mieux prendre en compte de tels scénarios en maintenant la généricité du paramètre résiduel ...args, et en déduisant de ce paramètre générique le n-uplet correspondant. Au lieu de déclarer chacune de ces surcharges, nous pouvons dire que le paramètre résiduel ...args de fn dérive d'un tableau, et que nous pouvons réutiliser cela pour le paramètre ...args passé dans call :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    function call<TS extends any[], R>(fn: (...args: TS) => R, ...args: TS): R {
        return fn(...args);
    }
    Quand la fonction call sera appelée, TypeScript essayera d'extraire la liste de paramètres de tout ce qui sera passé à fn, et transformera cela en un n-uplet:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    function foo(x: number, y: string): string {
        return (x + y).toLowerCase();
    }
     
    // `TS` is inferred as `[number, string]`
    call(foo, 100, "hello");
    Dans un premier temps, TypeScript infère le type générique TS en tant que [number, string] qui est ensuite utilisé sur le paramètre résiduel de call. La définition de la fonction call est transformée comme ce qui suit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    function call(fn: (...args: [number, string]) => string, ...args: [number, string]): string
    Puis, avec TypeScript 3.0, lorsqu'un n-uplet apparaît dans le type d'un paramètre résiduel, il est aplati (flattened) et expansé (spread) en autant de paramètres. Ce qui précède est considéré au final comme une suite de paramètres simples sans n-uplets :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    function call(fn: (arg1: number, arg2: string) => string, arg1: number, arg2: string): string
    Donc, le compilateur TypeScript 3.0 est capable de détecter les erreurs de type lorsque de mauvais paramètres sont passés :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    function call<TS extends any[], R>(fn: (...args: TS) => R, ...args: TS): R {
        return fn(...args);
    }
     
    call((x: number, y: string) => y, "hello", "world");
    //                                ~~~~~~~
    // Error! `string` isn't assignable to `number`!
    Le compilateur est aussi capable d'inférer les types à partir des autres paramètres :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    call((x, y) => { /* .... */ }, "hello", 100);
    //    ^  ^
    // `x` and `y` have their types inferred as `string` and `number` respectively.
    Encore mieux, il est possible de connaître depuis l'extérieur les types du n-uplet :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    function tuple<TS extends any[]>(...xs: TS): TS {
        return xs;
    }
     
    let x = tuple(1, 2, "hello"); // has type `[number, number, string]
    Cependant, en coulisse, pour que cette fonctionnalité soit disponible, il a fallu améliorer le typage des n-uplets dans TypeScript.

    Enrichissement du typage des n-uplets

    Les listes de paramètres ne sont pas simplement des listes ordonnées de types dans la mesure où par exemple les derniers paramètres peuvent être facultatifs :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    // Both `y` and `z` are optional here.
    function foo(x: boolean, y = 100, z?: string) {
        // ...
    }
     
    foo(true);
    foo(true, undefined, "hello");
    foo(true, 200);
    Le dernier paramètre peut aussi être un paramètre résiduel.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    // `rest` accepts any number of strings - even none!
    function foo(...rest: string[]) {
        // ...
    }
     
    foo();
    foo("hello");
    foo("hello", "world");
    Enfin, il existe une propriété à ne pas négliger concernant les listes de paramètres, à savoir qu'elles peuvent être vides :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    // Accepts no parameters.
    function foo() {
        // ...
    }
     
    foo();
    Donc, pour que les n-uplets puissent correspondre aux listes de paramètres, chacun de ces scénarios a dû être modélisé.

    Premièrement, les n-uplets autorisent maintenant les éléments facultatifs de fin :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    /**
     * 2D, or potentially 3D, coordinate.
     */
    type Coordinate = [number, number, number?];
    Le type Coordinate crée un n-uplet avec une propriété optionnelle nommée 2 -- l'élément à l'index 2 peut ne pas être défini. Fait intéressant, puisque les n-uplets utilisent des types littéraux numériques pour leurs propriétés de longueur, la propriété longueur de Coordinate a le type 2 | 3.

    Deuxièmement, les n-uplets autorisent maintenant les éléments résiduels à la fin.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    type OneNumberAndSomeStrings = [number, ...string[]];
    Les éléments résiduels introduisent un comportement ouvert intéressant aux n-uplets. Le type OneNumberAndSomeStrings ci-dessus requiert que sa première propriété soit un nombre et autorise 0 ou plusieurs strings. Indexer avec un nombre arbitraire retournera un string | number puisque l'indice n'est pas connu à l'avance. De même, puisque la longueur du n-uplet n'est pas connue à l'avance, la propriété length est simplement number.

    Fait à noter, quand aucun autre élément n'est présent, un élément résiduel dans un n-uplet est identique à lui-même:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    type Foo = [...number[]]; // Equivalent to `number[]`.
    Enfin, les n-uplets peuvent maintenant être vides ! Bien qu'il ne soit pas très utile en dehors des listes de paramètres, le type n-uplet vide peut être défini par []:

    Comme on peut s'y attendre, le n-uplet vide a une longueur de 0 et l'indexation avec un nombre renvoie le type never.

    Le type unknown

    Le type any est le type le plus permissif dans TypeScript. Dans la mesure où il englobe tous les types possibles, aucune vérification n'est réalisée avant l'utilisation des propriétés d'une valeur de type any. De plus, une variable de type any peut recevoir des valeurs de tout autre type lors d'une affectation.

    Son utilité n'est pas à démontrer, mais cela reste tout de même un peu laxiste dans pas mal de situations.

    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
    let foo: any = 10;
     
    // All of these will throw errors, but TypeScript
    // won't complain since `foo` has the type `any`.
    foo.x.prop;
    foo.y.prop;
    foo.z.prop;
    foo();
    new foo();
    upperCase(foo);
    foo `hello world!`;
     
    function upperCase(x: string) {
        return x.toUpperCase();
    }
    Il arrive des situations où nous voulons un type plus restrictif. Notamment dans le cas d'API où il peut être utile de signaler "cela peut être n'importe quelle valeur, donc vous devez effectuer un certain type de vérification avant de l'utiliser". On peut vouloir forcer les utilisateurs à faire de l'introspection sur les valeurs renvoyées dans une démarche de vérification.

    TypeScript 3.0 introduit un nouveau type appelé unknown qui fait exactement cela. Tout comme any, n'importe quelle valeur est assignable à unknown ; cependant, contrairement à any, nous ne pouvons pas accéder aux propriétés sur les valeurs avec le type unknown, ni ne pouvons les appeler / construire. De plus, les valeurs de type unknown ne peuvent être affectées uniquement qu'à des valeurs de type unknown ou any.

    Par exemple, si on change dans le précédent exemple l'utilisation de any par unknown, cela provoque une erreur à chaque utilisation de foo :

    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
    let foo: unknown = 10;
     
    // Since `foo` has type `unknown`, TypeScript
    // errors on each of these usages.
    foo.x.prop;
    foo.y.prop;
    foo.z.prop;
    foo();
    new foo();
    upperCase(foo);
    foo `hello world!`;
     
    function upperCase(x: string) {
        return x.toUpperCase();
    }
    Pour pouvoir manipuler après affection une variable de type unknown, une inférence de type (via un test) ou une assertion de type (as) vers un autre type que unknown est nécessaire.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    let foo: unknown = 10;
     
    function hasXYZ(obj: any): obj is { x: any, y: any, z: any } {
        return !!obj &&
            typeof obj === "object" &&
            "x" in obj &&
            "y" in obj &&
            "z" in obj;
    }
     
    // Using a user-defined type guard...
    if (hasXYZ(foo)) {
        // ...we're allowed to access certain properties again.
        foo.x.prop;
        foo.y.prop;
        foo.z.prop;
    }
     
    // We can also just convince TypeScript we know what we're doing
    // by using a type assertion.
    upperCase(foo as string);
     
    function upperCase(x: string) {
        return x.toUpperCase();
    }
    Il s'agit ici des principales nouveautés, mais il y en a d'autres concernant par exemple une meilleure prise en charge de ReactJS.

    source : Blog officiel de Microsoft

    Que pensez-vous de cette version majeure ?
    Les références de projet est-celle une fonctionnalité que vous pensez mettre en oeuvre prochainement dans vos projets ?
    Tutoriels et FAQ TypeScript

  2. #2
    Chroniqueur Actualités
    Avatar de Michael Guilloux
    Homme Profil pro
    Consultant
    Inscrit en
    juillet 2013
    Messages
    1 976
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 27
    Localisation : Côte d'Ivoire

    Informations professionnelles :
    Activité : Consultant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : juillet 2013
    Messages : 1 976
    Points : 62 917
    Points
    62 917
    Billets dans le blog
    2

    Par défaut TypeScript 3.0 est disponible en version stable

    TypeScript 3.0 est disponible en version stable
    un aperçu des nouveautés de cette version majeure du surensemble typé de JavaScript

    Le 31 juillet, Microsoft a annoncé la disponibilité de la version stable de TypeScript 3.0. Les nouveautés de cette nouvelle version majeure du surensemble typé de JavaScript ont été en grande partie présentées ici lors de la RC que Microsoft a annoncée le 12 juillet.

    TypeScript 3.0 permet par exemple le référencement de projets TypeScript externes, grâce à une nouvelle fonctionnalité appelée « Références de projet » ; une fonctionnalité que Microsoft considère d'ailleurs comme l'une des plus importantes sur lesquelles son équipe a travaillé dans cette version du surensemble typé de JavaScript. Concrètement, les références de projet permettent aux projets TypeScript de dépendre d'autres projets TypeScript, notamment en permettant aux fichiers tsconfig.json de référencer d'autres fichiers tsconfig.json. La spécification de ces dépendances facilite aussi la division de votre code en projets plus petits. Ci-dessous un aperçu de ce à quoi ressemble un tsconfig.json avec des références de projet :

    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
     
    // ./src/bar/tsconfig.json
    {
        "compilerOptions": {
            // Needed for project references.
            "composite": true,
            "declaration": true,
     
            // Other options...
            "outDir": "../../lib/bar",
            "strict": true, "module": "esnext", "moduleResolution": "node",
        },
        "references": [
            { "path": "../foo" }
        ]
    }
    Il y a deux nouveaux champs à noter ici : composite et references. Le champ references spécifie simplement les autres fichiers tsconfig.json (ou les dossiers qui les contiennent directement). Chaque référence n'est actuellement qu'un objet ne contenant qu'un champ path, et indique à TypeScript que la génération du projet en cours nécessite une génération préalable des autres projets référencés. Le champ composite, quant à lui, garantit que certaines options sont activées afin que ce projet puisse être référencé et généré de façon incrémentale pour tout projet qui en dépend.


    Comme autres fonctionnalités de TypeScript 3.0, Microsoft met en avant l'extraction et l'expansion de listes de paramètres avec des n-uplets, l'enrichissement du typage des n-uplets et le type unknown. Ce nouveau type est similaire (à quelques différences près) à any, le type le plus permissif de TypeScript. Tout comme any, n'importe quelle valeur est assignable à unknown . Cependant, contrairement à any, nous ne pouvons pas accéder aux propriétés sur les valeurs avec le type unknown, ni les appeler / construire. De plus, les valeurs de type unknown ne peuvent être affectées uniquement qu'à des valeurs de type unknown ou any.

    Dans le billet relatif à l'annonce de la version stable de TypeScript 3.0, Microsoft cite encore, parmi les principales nouveautés, des améliorations des messages d'erreur et de l'expérience utilisateur, mais aussi une meilleure prise en charge de ReactJS, ainsi que des améliorations de productivité lors de l'édition de code TypeScript. Vous trouverez plus de détails sur ces nouveautés et la liste exhaustive des changements sur le blog TypeScript.

    Source : Blog TypeScript

    Et vous ?

    Utilisez-vous TypeScript ?
    Qu'en pensez-vous par rapport aux autres langages de la famille JavaScript ?
    Que pensez-vous des nouveautés de cette version ?
    Qu'attendez-vous pour les versions à venir ?
    Contribuez au club : Corrections, suggestions, critiques, ... : Contactez le service news et Rédigez des actualités

Discussions similaires

  1. Réponses: 3
    Dernier message: 02/08/2015, 21h22
  2. Release candidate enfin !
    Par talu3000 dans le forum Silverlight
    Réponses: 20
    Dernier message: 01/10/2008, 09h31
  3. Réponses: 6
    Dernier message: 02/06/2008, 18h57
  4. Réponses: 0
    Dernier message: 23/05/2008, 11h26
  5. Réponses: 97
    Dernier message: 03/12/2007, 10h39

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