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 |
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.
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 |
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();
}
} |
| Code : | Sélectionner tout |
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();
});
} |
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 |
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);
} |
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 |
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!"); |
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 |
1 2 3 4 5 | function createStreetLight<C extends string>(colors: C[], defaultColor?: C) {
// ...
}
createStreetLight(["red", "yellow", "green"], "red"); |
| Code : | Sélectionner tout |
1 2 | // Oops! This undesirable, but is allowed! createStreetLight(["red", "yellow", "green"], "blue"); |
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 |
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'. |
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 |
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'. |
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 |
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";
}); |
| Code : | Sélectionner tout |
1 2 3 4 | const myObj = {
even: [0, 2, 4],
odd: [1, 3, 5],
}; |
| Code : | Sélectionner tout |
1 2 3 | const myObj = Map.groupBy(array, (num, index) => {
return num % 2 === 0 ? "even" : "odd";
}); |
| Code : | Sélectionner tout |
1 2 3 4 | const myObj = new Map();
myObj.set("even", [0, 2, 4]);
myObj.set("odd", [1, 3, 5]); |
| Code : | Sélectionner tout |
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'. |
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...
La fin de cet article est réservée aux abonnés. Soutenez le Club Developpez.com en prenant un abonnement pour que nous puissions continuer à vous proposer des publications.