Si vous n'êtes pas encore familiarisé avec TypeScript, il s'agit d'un langage qui s'appuie sur JavaScript en ajoutant des types vérifiés statiquement. Lorsque vous utilisez des types statiques, vous pouvez exécuter le compilateur TypeScript pour rechercher les bogues tels que les fautes de frappe et les incohérences dans les formes de vos données, et obtenir des suggestions pratiques. Ces types ne changent pas votre programme, et vous pouvez les supprimer pour vous conserver un JavaScript propre et lisible. Au-delà de la détection de bogues dans votre code, TypeScript vous aide également à écrire du code, car les types peuvent alimenter des outils utiles tels que la saisie semi-automatique, la définition et le renommage dans votre éditeur.Les améliorations apportées au type Awaited et Promise
TypeScript 4.5 introduit un nouveau type d'utilitaire appelé type Awaited. Ce type est destiné à modéliser des opérations telles que les fonctions await et async, ou la méthode .then() sur les Promise (en particulier la manière dont elles déballent de manière récursive les Promise).
| Code TypeScript : | Sélectionner tout |
1 2 3 4 5 6 7 8 | // A = string type A = Awaited<Promise<string>>; // B = number type B = Awaited<Promise<Promise<number>>>; // C = boolean | number type C = Awaited<boolean | Promise<number>>; |
| Code TypeScript : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | declare function MaybePromise<T>(value: T): T | Promise<T> | PromiseLike<T>; async function doSomething(): Promise<[number, number]> { const result = await Promise.all([ MaybePromise(100), MaybePromise(200) ]); // Error! // // [number | Promise<100>, number | Promise<200>] // // is not assignable to type // // [number, number] return result; } |
Prise en charge de lib à partir de node_modules
Pour garantir que la prise en charge de TypeScript et JavaScript fonctionne correctement, TypeScript regroupe une série de fichiers de déclaration (fichiers .d.ts). Ces fichiers de déclaration représentent les API disponibles dans le langage JavaScript et les API DOM de navigateur standard. Bien qu'il existe des valeurs par défaut raisonnables en fonction de votre cible, vous pouvez choisir les fichiers de déclaration que votre programme utilise en configurant le paramètre lib dans le fichier tsconfig.json.
Il y a cependant deux inconvénients occasionnels à inclure ces fichiers de déclaration avec TypeScript :
- Lorsque vous mettez à niveau TypeScript, vous êtes également obligé de gérer les modifications apportées aux fichiers de déclaration intégrés de TypeScript, ce qui peut être un défi lorsque les API DOM changent aussi fréquemment qu'elles le font.
- Il est difficile de personnaliser ces fichiers pour qu'ils correspondent à vos besoins avec les besoins des dépendances de votre projet (par exemple, si vos dépendances déclarent qu'elles utilisent les API DOM, vous pourriez également être obligé d'utiliser les API DOM).
TypeScript 4.5 introduit un moyen de remplacer une bibliothèque intégrée spécifique d'une manière similaire au fonctionnement du support de @types/. Au moment de décider quels fichiers lib TypeScript doit inclure, il recherchera d'abord un package @typescript/lib-* étendu dans node_modules. Par exemple, lors de l'inclusion de dom en tant qu'option dans lib, TypeScript utilisera les types dans node_modules/@typescript/lib-dom s'ils sont disponibles.
Vous pouvez ensuite utiliser votre gestionnaire de packages pour installer un package spécifique à prendre en charge pour une bibliothèque donnée. Par exemple, TypeScript publie aujourd'hui des versions des API DOM sur @types/web. Si vous souhaitez verrouiller votre projet sur une version spécifique des API DOM, vous pouvez l'ajouter à votre package.json*:
| Code TypeScript : | Sélectionner tout |
1 2 3 4 5 | { "dependencies": { "@typescript/lib-dom": "npm:@types/web" } } |
Types de chaîne de template en tant que discriminants
TypeScript 4.5 peut désormais restreindre les valeurs qui ont des types de chaîne de template et reconnaît également les types de chaîne de template comme discriminants.
À titre d'exemple, les éléments suivants échouaient auparavant, mais les vérifications de type sont désormais réussies dans TypeScript 4.5 :
| Code TypeScript : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | export interface Success { type: `${string}Success`; body: string; } export interface Error { type: `${string}Error`; message: string; } export function handler(r: Success | Error) { if (r.type === "HttpSuccess") { // 'r' has type 'Success' let token = r.body; } } |
TypeScript prend désormais en charge un nouveau paramètre de module*: es2022. La principale fonctionnalité de --module es2022 est l'await du niveau supérieur, ce qui signifie que vous pouvez utiliser await[/B] en dehors des fonctions [C]async. Cela était déjà pris en charge dans --module esnext (et maintenant --module nodenext), mais es2022 est la première cible stable pour cette fonctionnalité.
Élimination de la récursivité de queue sur les types conditionnels
TypeScript doit souvent échouer gracieusement lorsqu'il détecte une récursivité éventuellement infinie, ou toute extension de type qui peut prendre beaucoup de temps et affecter votre expérience d'éditeur. En conséquence, TypeScript dispose d'heuristiques pour s'assurer qu'il ne déraille pas en essayant de séparer un type infiniment profond, ou en travaillant avec des types qui génèrent beaucoup de résultats intermédiaires.
| Code TypeScript : | Sélectionner tout |
1 2 3 4 5 6 | type InfiniteBox<T> = { item: InfiniteBox<T> } type Unpack<T> = T extends { item: infer U } ? Unpack<U> : T; // error: Type instantiation is excessively deep and possibly infinite. type Test = Unpack<InfiniteBox<number>> |
| Code TypeScript : | Sélectionner tout |
1 2 3 4 5 | type TrimLeft<T extends string> = T extends ` ${infer Rest}` ? TrimLeft<Rest> : T; // Test = "hello" | "world" type Test = TrimLeft<" hello" | " world">; |
| Code TypeScript : | Sélectionner tout |
1 2 3 4 5 | type TrimLeft<T extends string> = T extends ` ${infer Rest}` ? TrimLeft<Rest> : T; // error: Type instantiation is excessively deep and possibly infinite. type Test = TrimLeft<" oops">; |
TrimLeft est écrit d'une manière qui est récursive dans une branche. Lorsqu'il s'appelle à nouveau, il renvoie immédiatement le résultat et ne fait rien avec. Étant donné que ces types n'ont pas besoin de créer de résultats intermédiaires, ils peuvent être implémentés plus rapidement et d'une manière qui évite de déclencher de nombreuses heuristiques de récursivité de type intégrées à TypeScript.
C'est pourquoi TypeScript 4.5 effectue une certaine élimination de la récursion finale sur les types conditionnels. Tant qu'une branche d'un type conditionnel est simplement un autre type conditionnel, TypeScript peut éviter les instanciations intermédiaires. Il existe encore des heuristiques pour s'assurer que ces types ne dérapent pas, mais ils sont beaucoup plus généreux.
Gardez à l'esprit que le type suivant ne sera pas optimisé, car il utilise le résultat d'un type conditionnel en l'ajoutant à une union.
| Code TypeScript : | Sélectionner tout |
1 2 | type GetChars<S> = S extends `${infer Char}${infer Rest}` ? Char | GetChars<Rest> : never; |
| Code TypeScript : | Sélectionner tout |
1 2 3 | type GetChars<S> = GetCharsHelper<S, never>; type GetCharsHelper<S, Acc> = S extends `${infer Char}${infer Rest}` ? GetCharsHelper<Rest, Char | Acc> : Acc; |
Dans certains cas, TypeScript ne peut pas détecter que vous utilisez une importation. Par exemple, prenons le code suivant*:
| Code TypeScript : | Sélectionner tout |
1 2 3 | import { Animal } from "./animal.js"; eval("console.log(new Animal().isDangerous())"); |
| Code TypeScript : | Sélectionner tout |
1 2 3 4 5 6 | <!-- A .svelte File --> <script> import { someFunc } from "./some-module.js"; </script> <button on:click={someFunc}>Click me!</button> |
| Code TypeScript : | Sélectionner tout |
1 2 3 4 5 6 | <!-- A .vue File --> <script setup> import { someFunc } from "./some-module.js"; </script> <button @click="someFunc">Click me!</button> |
Notez que cet indicateur a une exigence particulière lorsqu'il est combiné avec --isolatedModules : les types importés doivent être marqués comme étant uniquement de type car les compilateurs qui traitent des fichiers uniques à la fois n'ont aucun moyen de savoir si les importations sont des valeurs qui semblent inutilisées, ou un type qui doit être supprimé afin d'éviter un crash d'exécution.
| Code TypeScript : | Sélectionner tout |
1 2 3 4 5 6 | // Which of these is a value that should be preserved? tsc knows, but `ts.transpileModule`, // ts-loader, esbuild, etc. don't, so `isolatedModules` gives an error. import { someFunc, BaseType } from "./some-module.js"; // ^^^^^^^^ // Error: 'BaseType' is a type and must be imported using a type-only import // when 'preserveValueImports' and 'isolatedModules' are both enabled. |
Source : Microsoft
Vous avez lu gratuitement 898 articles depuis plus d'un an.
Soutenez le club developpez.com en souscrivant un abonnement pour que nous puissions continuer à vous proposer des publications.
Soutenez le club developpez.com en souscrivant un abonnement pour que nous puissions continuer à vous proposer des publications.