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

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

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

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

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

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

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

Je m'inscris !

Microsoft annonce la disponibilité de TypeScript 3.2 qui s'accompagne de nombreuses nouveautés
Comme la prise en charge de BigInt

Le , par Stéphane le calme

552PARTAGES

12  0 
strictBindCallApply

TypeScript 3.2 introduit une vérification plus stricte de bind, call et apply. Mais qu'est ce que cela signifie en réalité ?

En JavaScript, bind, apply et call sont des méthodes sur des fonctions qui nous permettent de faire des choses comme lier this, appliquer partiellement des arguments, appeler des fonctions ayant une valeur différente pour this et appeler des fonctions ayant un tableau en arguments.

Malheureusement, à ses débuts, TypeScript n’était pas en mesure de modéliser ces fonctions, et bind, call et apply étaient tous typés pour prendre un nombre quelconque d'arguments et renvoyer any. De plus, les fonctions fléchées et les arguments rest / spread de ES2015 ont fourni à Microsoft une nouvelle syntaxe qui selon l’éditeur, permet d’exprimer plus facilement ce que certaines de ces méthodes font - et de manière plus efficace.

Rappelons qu’une expression de fonction fléchée (arrow function en anglais) permet d'avoir une syntaxe plus courte que les expressions de fonction et ne possède pas ses propres valeurs pour this, arguments, super, ou new.target. Les fonctions fléchées sont souvent anonymes et ne sont pas destinées à être utilisées pour déclarer des méthodes.

Néanmoins, suite à la demande, Microsoft a été conduit à revoir le sujet récemment. L’éditeur affirme avoir réalisé que deux fonctionnalités ouvraient les bonnes abstractions pour typer avec précision bind, call et apply sans codage en dur:
  • this type de paramètre à partir de TypeScript 2.0
  • Modélisation des listes de paramètres avec des types de n-uplets à partir de TypeScript 3.0

L’équipe explique que « La combinaison de ces deux éléments permet de s'assurer que nos utilisations de bind, call et apply sont plus strictement vérifiées lorsque nous utilisons un nouvel indicateur appelé strictBindCallApply. Lors de l'utilisation de ce nouvel indicateur, les méthodes sur les objets appelables sont décrites par un nouveau type global appelé CallableFunction, qui déclare des versions plus strictes des signatures pour bind, call et apply. De même, toutes les méthodes sur des objets constructibles (mais non appelables) sont décrites par un nouveau type global appelé NewableFunction ».

À titre d'exemple, nous pouvons voir comment Function.prototype.apply agit sous ce comportement:

Code TypeScript : Sélectionner tout
1
2
3
4
5
6
7
8
function foo(a: number, b: string): string { 
    return a + b; 
} 
  
let a = foo.apply(undefined, [10]);              // error: too few argumnts 
let b = foo.apply(undefined, [10, 20]);          // error: 2nd argument is a number 
let c = foo.apply(undefined, [10, "hello", 30]); // error: too many arguments 
let d = foo.apply(undefined, [10, "hello"]);     // okay! returns a string

Mises en garde

Un inconvénient de cette nouvelle fonctionnalité est qu’en raison de certaines limitations, bind, call et apply ne peuvent pas encore totalement modéliser les fonctions génériques ou les fonctions surchargées. Lorsque vous utilisez ces méthodes sur une fonction générique, les paramètres de type sont remplacés par le type d'objet vide ({}), et lorsqu'ils sont utilisés sur une fonction avec des surcharges, seule la dernière surcharge sera modélisée.

Objet étendu sur des types génériques

JavaScript prend en charge un moyen pratique de copier les propriétés existantes d'un objet existant dans un nouvel objet qui en sera donc l’extension. Pour étendre un objet existant dans un nouvel objet, vous définissez un élément avec trois points consécutifs (...) comme suit:

Code TypeScript : Sélectionner tout
1
2
3
4
5
let person = { name: "Daniel", location: "New York City" }; 
  
// My secret revealed, I have two clones! 
let shallowCopyOfPerson = { ...person }; 
let shallowCopyOfPersonWithDifferentLocation = { ...person, location: "Seattle" };

TypeScript fait un très bon travail ici lorsqu'il dispose de suffisamment d'informations sur le type. Le système de typage essaie de modéliser le comportement des extensions et surcharge de nouvelles propriétés, essaie d’ignorer les méthodes, etc. Mais jusqu’à présent, il ne fonctionnait pas du tout avec les génériques.

Code TypeScript : Sélectionner tout
1
2
3
4
function merge<T, U>(x: T, y: U) { 
    // Previously an error! 
    return { ...x, ...y }; 
}

Pour l’équipe, « C'était une erreur car nous n'avions aucun moyen d'exprimer le type de retour de merge. Il n'y avait pas de syntaxe (ni de sémantique) pouvant exprimer deux types inconnus qui allait en former un nouveau représentant leur extension.

« Nous aurions pu imaginer un nouveau concept dans le système de types appelé “type à extension d'objet”, et nous avions en fait une proposition à cet effet. Il s’agit essentiellement d’un nouvel opérateur de type qui ressemble à {... T, ... U} pour refléter la syntaxe d’un objet étendu ».

Lorsque T et U sont connus, ce type va s’écraser pour former un nouveau type d’objet.

Cependant, cela est assez complexe et nécessite l'ajout de nouvelles règles appliquées aux types pour des relations et des inférences. Alors que l’équipe a exploré plusieurs pistes, elle est récemment arrivée à deux conclusions:

  • Pour la plupart des utilisations des extensions en JavaScript, ils modélisaient bien le comportement avec les types d'intersection (c'est-à-dire Foo & Bar).
  • Object.assign - une fonction qui présente l’essentiel du comportement des extensions d’objets - est déjà modélisée à l’aide de types d’intersection, et l’équipe n’a constaté que très peu de réactions négatives à ce sujet.

Etant donné que les intersections modélisent les cas courants et que leur compréhension est relativement facile à la fois pour les utilisateurs et le système de types, TypeScript 3.2 autorise maintenant les extensions d’objets sur des génériques et les modélise à l’aide d’intersections:

Code TypeScript : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Returns 'T & U' 
function merge<T, U>(x: T, y: U) { 
    return { ...x, ...y }; 
} 
  
// Returns '{ name: string, age: number, greeting: string } & T' 
function foo<T>(obj: T) { 
    let person = { 
        name: "Daniel", 
        age: 26 
    }; 
  
    return { ...person, greeting: "hello", ...obj }; 
}

Héritage de configuration via les packages node_modules

Pendant longtemps, TypeScript a pris en charge l'extension des fichiers tsconfig.json à l'aide du champ extend.

Code TypeScript : Sélectionner tout
1
2
3
4
5
6
7
8
{ 
    "extends": "../tsconfig-base.json", 
    "include": ["./**/*"] 
    "compilerOptions": { 
        // Override certain options on a project-by-project basis. 
        "strictBindCallApply": false, 
    } 
}

Cette fonctionnalité est très utile pour éviter la duplication de configuration qui risquerait de faire perdre la synchronisation, mais elle fonctionne vraiment mieux lorsque plusieurs projets sont co-localisés dans le même référentiel afin que chaque projet puisse référencer une « base » commune tsconfig.json.

Toutefois, pour certaines équipes, les projets sont écrits et publiés comme des packages totalement indépendants. Ces projets ne disposent pas d’un fichier commun auquel ils peuvent faire référence. Par conséquent, les utilisateurs peuvent créer un package et une référence distincts:

Code TypeScript : Sélectionner tout
1
2
3
4
5
6
7
8
{ 
    "extends": "../node_modules/@my-team/tsconfig-base/tsconfig.json", 
    "include": ["./**/*"] 
    "compilerOptions": { 
        // Override certain options on a project-by-project basis. 
        "strictBindCallApply": false, 
    } 
}

Cependant, aller dans les répertoires parents avec une série de ../s et accéder directement à node_modules pour saisir un fichier spécifique semble un peu difficile.

TypeScript 3.2 résout maintenant tsconfig.jsons à partir de node_modules. Lors de l'utilisation d'un chemin nu pour le champ "extend" dans tsconfig.json, TypeScript plongera dans les packages node_modules à votre place.

Code TypeScript : Sélectionner tout
1
2
3
4
5
6
7
8
{ 
    "extends": "@my-team/tsconfig-base", 
    "include": ["./**/*"] 
    "compilerOptions": { 
        // Override certain options on a project-by-project basis. 
        "strictBindCallApply": false, 
    } 
}

Ici, TypeScript montera dans les dossiers node_modules à la recherche d'un paquet @ my-team / tsconfig-base. Pour chacun de ces packages, TypeScript vérifie d'abord si package.json contient un champ "tsconfig" et, le cas échéant, TypeScript essaiera de charger un fichier de configuration à partir de ce champ. Si aucun n'existe, TypeScript essaiera de lire à partir d'un fichier tsconfig.json à la racine. Cette procédure est similaire au processus de recherche des fichiers .js dans les packages utilisés par Node et au processus de recherche .d.ts déjà utilisé par TypeScript.

Cette fonctionnalité peut s'avérer extrêmement utile pour les grandes organisations ou les projets comportant de nombreuses dépendances distribuées.

Diagnostiquer tsconfig.json avec --showConfig

tsc, le compilateur TypeScript, prend en charge un nouvel indicateur appelé --showConfig. Lors de l'exécution de tsc --showConfig, TypeScript calculera le tsconfig.json effectif (après avoir calculé les options héritées du champ expand) et va afficher ce résultat. Cela peut être utile pour diagnostiquer les problèmes de configuration en général.

BigInt

BigInt fait partie d’une proposition à venir dans ECMAScript qui nous permet de modéliser des entiers théoriquement grands de façon arbitraire. TypeScript 3.2 apporte la vérification de type pour BigInt, ainsi que la prise en charge de l'émission de littéraux BigInt lors du ciblage de esnext.

La prise en charge de BigInt dans TypeScript introduit un nouveau type primitif appelé bigint (tout en minuscule). Vous pouvez obtenir un bigint en appelant la fonction BigInt () ou en écrivant un littéral BigInt en ajoutant un n à la fin de tout littéral numérique entier:

Code TypeScript : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let foo: bigint = BigInt(100); // the BigInt function 
let bar: bigint = 100n;        // a BigInt literal 
  
// *Slaps roof of fibonacci function* 
// This bad boy returns ints that can get *so* big! 
function fibonacci(n: bigint) { 
    let result = 1n; 
    for (let last = 0n, i = 0n; i < n; i++) { 
        const current = result; 
        result += last; 
        last = current; 
    } 
    return result; 
} 
  
fibonacci(10000n)

Bien que vous puissiez imaginer une interaction étroite entre number et bigint, ces deux domaines sont distincts.

Code TypeScript : Sélectionner tout
1
2
3
4
5
declare let foo: number; 
declare let bar: bigint; 
  
foo = bar; // error: Type 'bigint' is not assignable to type 'number'. 
bar = foo; // error: Type 'number' is not assignable to type 'bigint'.

Comme spécifié dans ECMAScript, le mélange de nombres et de bigints dans des opérations arithmétiques est une erreur. Vous devrez convertir explicitement les valeurs en BigInt.

Code TypeScript : Sélectionner tout
1
2
3
console.log(3.141592 * 10000n);     // error 
console.log(3145 * 10n);            // error 
console.log(BigInt(3145) * 10n);    // okay!

Il est également important de noter que les bigint produisent une nouvelle chaîne lors de l'utilisation de l'opérateur typeof: la chaîne "bigint".

Code TypeScript : Sélectionner tout
1
2
3
4
5
6
7
8
function whatKindOfNumberIsIt(x: number | bigint) { 
    if (typeof x === "bigint") { 
        console.log("'x' is a bigint!"); 
    } 
    else { 
        console.log("'x' is a floating-point number"); 
    } 
}

Mises en garde

Comme mentionné plus haut, le support BigInt n'est disponible que pour la cible esnext. Cela n’est peut-être pas évident, mais parce que BigInt a un comportement différent pour les opérateurs mathématiques tels que +, -, *, etc., fournir une fonctionnalité pour les cibles plus anciennes où la fonctionnalité n’existe pas (comme es2017 et les versions antérieures) impliquerait la réécriture de chacune de ces opérations. TypeScript aurait besoin d'affecter le comportement correct en fonction du type. Ainsi, tout ajout, concaténation de chaîne, multiplication, etc. impliquerait un appel de fonction.

Pour cette raison, Microsoft n’a aucun projet immédiat de fournir un support au niveau inférieur. L’équipe note tout de même que Node 11 et les versions plus récentes de Chrome prennent déjà en charge cette fonctionnalité. Vous pourrez donc utiliser BigInt dessus pour cibler esnext.

Source : Microsoft

Voir aussi :

TypeScript 3.1 est disponible, cette version s'accompagne des redirections de versions ainsi que des types de tableau et de tuple mappables
Google s'oriente vers TypeScript et voici pourquoi, selon Evan Martin, un ingénieur de la firme qui travaille sur le langage
TypeScript 3.0 est disponible en version stable : un aperçu des nouveautés de cette version majeure du surensemble typé de JavaScript
TypeScript 2.9 est disponible et intègre plusieurs nouveautés, le langage continue de compléter son système de typage

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

Avatar de kilroyFR
Membre éprouvé https://www.developpez.com
Le 02/12/2018 à 10:08
Genial. Typescript m'a reconcilié depuis des années avec javascript et ses syntaxes barbares et c'est tres bien que M$ continue a le mettre en avant.
1  1 
Avatar de Paleo
Membre éclairé https://www.developpez.com
Le 03/12/2018 à 11:28
Citation Envoyé par Stéphane le calme Voir le message
L’équipe note tout de même que Node 11 et les versions plus récentes de Chrome prennent déjà en charge cette fonctionnalité. Vous pourrez donc utiliser BigInt dessus pour cibler esnext.
En fait les BigInt sont implémentés sur les versions récentes de Node 10.
0  0 
Avatar de Sodium
Membre extrêmement actif https://www.developpez.com
Le 01/02/2019 à 8:35
Citation Envoyé par kilroyFR Voir le message
Genial. Typescript m'a reconcilié depuis des années avec javascript et ses syntaxes barbares et c'est tres bien que M$ continue a le mettre en avant.
Attention, il est très mal vu sur ce forum de pointer les lacunes de JavaScript.
JavaScript est un langage parfait et si tu n'apprécies pas c'est forcément parce que tu es un débutant qui n'a jamais étudié sérieusement le langage
0  3