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 !

La version 5.3 de TypeScript est désormais disponible, et ajoute la prise en charge des attributs d'importation
Ainsi qu'un support stable de resolution-mode dans les types d'importation

Le , par Anthony

931PARTAGES

4  0 
Aujourd'hui, Microsoft a le plaisir d'annoncer la sortie de TypeScript 5.3, la dernière version du langage de programmation libre et open source développé par Microsoft qui a pour but d'améliorer et de sécuriser la production de code JavaScript.

Si vous ne connaissez pas TypeScript, il s'agit d'un langage qui ajoute la syntaxe de type à JavaScript pour apporter la vérification de type. Le contrôle de type permet de détecter toutes sortes de problèmes, comme les fautes de frappe et l'oubli de la vérification de la présence de null et de undefined. Mais les types vont bien au-delà de la vérification de type - les mêmes analyses du vérificateur de type de TypeScript sont utilisées pour des outils d'édition riches comme l'auto-complétion, la navigation dans le code et les refactorisations. En fait, si vous avez écrit du JavaScript dans des éditeurs tels que Visual Studio ou VS Code, cette expérience est alimentée par TypeScript !

Pour commencer à utiliser TypeScript, vous pouvez l'obtenir via NuGet, ou via npm avec la commande suivante :

Code : Sélectionner tout
npm install -D typescript



Quelles sont les nouveautés depuis la bêta et la RC ?

Depuis la sortie de la version candidate, aucun changement majeur n'a eu lieu.

Depuis la sortie de la version bêta, une option a été ajoutée pour privilégier les auto-importations de type uniquement lorsque c'est possible.

La version bêta permettait d'utiliser le mode de résolution pour tous les paramètres de résolution des modules, mais ne le documentait pas.

Attributs d'importation

TypeScript 5.3 prend en charge les dernières mises à jour de la proposition relative aux attributs d'importation.

L'un des cas d'utilisation des attributs d'importation est de fournir des informations sur le format attendu d'un module au moteur d'exécution.

Code : Sélectionner tout
1
2
3
// We only want this to be interpreted as JSON,
// not a runnable/malicious JavaScript file with a `.json` extension.
import obj from "./something.json" with { type: "json" };

Le contenu de ces attributs n'est pas vérifié par TypeScript car ils sont spécifiques à l'hôte, et sont simplement laissés tels quels afin que les navigateurs et les runtimes puissent les gérer (et éventuellement commettre des erreurs).

Code : Sélectionner tout
1
2
3
// TypeScript is fine with this.
// But your browser? Probably not.
import * as foo from "./foo.js" with { type: "fluffy bunny" };

Les appels dynamiques import() peuvent également utiliser les attributs d'importation par le biais d'un second argument.

Code : Sélectionner tout
1
2
3
const obj = await import("./something.json", {
    with: { type: "json" }
});

Le type attendu de ce second argument est défini par un type appelé ImportCallOptions, qui par défaut attend simplement une propriété appelée with.

Notez que les attributs d'importation sont une évolution d'une proposition antérieure appelée "assertions d'importation", qui a été mise en œuvre dans TypeScript 4.5. La différence la plus évidente est l'utilisation du mot-clé with au lieu du mot-clé assert. Mais la différence la moins visible est que les moteurs d'exécution sont désormais libres d'utiliser les attributs pour guider la résolution et l'interprétation des chemins d'importation, alors que les assertions d'importation ne pouvaient affirmer certaines caractéristiques qu'après le chargement d'un module.

Au fil du temps, TypeScript abandonnera l'ancienne syntaxe des assertions d'importation au profit de la syntaxe proposée pour les attributs d'importation. Le code existant utilisant assert devrait migrer vers le mot-clé with. Le nouveau code qui a besoin d'un attribut d'importation devrait utiliser exclusivement with.

Support stable resolution-mode dans les types d'importation

Dans TypeScript 4.7, TypeScript a ajouté le support d'un attribut resolution-mode dans /// <reference types="..." /> pour contrôler si un spécificateur doit être résolu via la sémantique import ou require.

Code : Sélectionner tout
1
2
3
4
5
/// <reference types="pkg" resolution-mode="require" />

// or

/// <reference types="pkg" resolution-mode="import" />

Un champ correspondant a également été ajouté aux assertions d'importation sur les importations de type uniquement ; cependant, il n'était pris en charge que dans les versions nocturnes de TypeScript. Le raisonnement était que dans l'esprit, les assertions d'importation n'étaient pas destinées à guider la résolution des modules. Cette fonctionnalité a donc été livrée à titre expérimental en mode "nightly only" afin d'obtenir davantage de retours.

Mais étant donné que les attributs d'importation peuvent guider la résolution, et que des cas d'utilisation raisonnables ont été observés, TypeScript 5.3 prend désormais en charge l'attribut resolution-mode pour type import.

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
// Resolve `pkg` as if we were importing with a `require()`
import type { TypeFromRequire } from "pkg" with {
    "resolution-mode": "require"
};

// Resolve `pkg` as if we were importing with an `import`
import type { TypeFromImport } from "pkg" with {
    "resolution-mode": "import"
};

export interface MergedType extends TypeFromRequire, TypeFromImport {}

Ces attributs d'importation peuvent également être utilisés sur les types import().

Code : Sélectionner tout
1
2
3
4
5
6
7
export type TypeFromRequire =
    import("pkg", { with: { "resolution-mode": "require" } }).TypeFromRequire;

export type TypeFromImport =
    import("pkg", { with: { "resolution-mode": "import" } }).TypeFromImport;

export interface MergedType extends TypeFromRequire, TypeFromImport {}

Support de resolution-mode dans tous les modes du module

Auparavant, l'utilisation de resolution-mode n'était autorisée que pour les options moduleResolution node16 et nodenext. Pour faciliter la recherche de modules spécifiques à des fins de type, resolution-mode fonctionne désormais de manière appropriée dans toutes les autres options moduleResolution telles que bundler, node10, et ne provoque tout simplement pas d'erreur sous classic.

Rétrécissement dans un switch (true)

TypeScript 5.3 peut maintenant effectuer un rétrécissement basé sur des conditions dans chaque clause case à l'intérieur d'un switch (true).

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function f(x: unknown) {
    switch (true) {
        case typeof x === "string":
            // 'x' is a 'string' here
            console.log(x.toUpperCase());
            // falls through...

        case Array.isArray(x):
            // 'x' is a 'string | any[]' here.
            console.log(x.length);
            // falls through...

        default:
          // 'x' is 'unknown' here.
          // ...
    }
}

Rétrécissement sur des comparaisons avec des booléens

Il peut arriver que vous ayez à effectuer une comparaison directe avec true ou false dans une condition. Il s'agit généralement de comparaisons non nécessaires, mais vous pouvez les préférer pour des raisons de style ou pour éviter certains problèmes liés à la véracité de JavaScript. Quoi qu'il en soit, TypeScript ne reconnaissait pas ces formes lorsqu'il procédait à un rétrécissement.

TypeScript 5.3 se met désormais au diapason et comprend ces expressions lors du rétrécissement des variables.

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
interface A {
    a: string;
}

interface B {
    b: string;
}

type MyType = A | B;

function isA(x: MyType): x is A {
    return "a" in x;
}

function someFn(x: MyType) {
    if (isA(x) === true) {
        console.log(x.a); // works!
    }
}

Rétrécissement de instanceof avec Symbol.hasInstance

Une caractéristique légèrement ésotérique de JavaScript est qu'il est possible d'outrepasser le comportement de l'opérateur instanceof. Pour ce faire, la valeur à droite de l'opérateur instanceof doit avoir une méthode spécifique nommée par Symbol.hasInstance.

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
class Weirdo {
    static [Symbol.hasInstance](testedValue) {
        // wait, what?
        return testedValue === undefined;
    }
}

// false
console.log(new Thing() instanceof Weirdo);

// true
console.log(undefined instanceof Weirdo);

Pour mieux modéliser ce comportement dans instanceof, TypeScript vérifie maintenant si une telle méthode [Symbol.hasInstance] existe et est déclarée comme une fonction de prédicat de type. Si c'est le cas, la valeur testée à gauche de l'opérateur instanceof sera restreinte de manière appropriée par ce prédicat de type.

Code : Sélectionner tout
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
26
27
28
29
30
31
32
33
34
35
36
37
38
interface PointLike {
    x: number;
    y: number;
}

class Point implements PointLike {
    x: number;
    y: number;

    constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
    }

    distanceFromOrigin() {
        return Math.sqrt(this.x ** 2 + this.y ** 2);
    }

    static [Symbol.hasInstance](val: unknown): val is PointLike {
        return !!val && typeof val === "object" &&
            "x" in val && "y" in val &&
            typeof val.x === "number" &&
            typeof val.y === "number";
    }
}


function f(value: unknown) {
    if (value instanceof Point) {
        // Can access both of these - correct!
        value.x;
        value.y;

        // Can't access this - we have a 'PointLike',
        // but we don't *actually* have a 'Point'.
        value.distanceFromOrigin();
    }
}

Comme vous pouvez le voir dans cet exemple, Point définit sa propre méthode [Symbol.hasInstance]. Elle agit en fait comme une protection de type personnalisée sur un type distinct appelé PointLike. Dans la fonction f, il a été possible de réduire la valeur value à un PointLike avec instanceof, mais pas à un Point. Cela signifie qu'il est possible d'accéder aux propriétés x et y, mais pas à la méthode distanceFromOrigin.

Vérification des accès à la propriété super sur les champs d'instance

En JavaScript, il est possible d'accéder à une déclaration dans une classe de base grâce au mot-clé super.

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Base {
    someMethod() {
        console.log("Base method called!");
    }
}

class Derived extends Base {
    someMethod() {
        console.log("Derived method called!");
        super.someMethod();
    }
}

new Derived().someMethod();
// Prints:
//   Derived method called!
//   Base method called!

Cela diffère de l'écriture de quelque chose comme this.someMethod(), puisque cela pourrait invoquer une méthode surchargée. Il s'agit d'une distinction subtile, rendue encore plus subtile par le fait que les deux peuvent souvent être interchangeables si une déclaration n'est jamais surchargée.

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Base {
    someMethod() {
        console.log("someMethod called!");
    }
}

class Derived extends Base {
    someOtherMethod() {
        // These act identically.
        this.someMethod();
        super.someMethod();
    }
}

new Derived().someOtherMethod();
// Prints:
//   someMethod called!
//   someMethod called!

Le problème de leur interchangeabilité est que super ne fonctionne que sur les membres déclarés dans le prototype - pas sur les propriétés d'instance. Cela signifie que si vous écrivez super.someMethod(), mais que someMethod est défini comme un champ, vous obtiendrez une erreur d'exécution.

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Base {
    someMethod = () => {
        console.log("someMethod called!");
    }
}

class Derived extends Base {
    someOtherMethod() {
        super.someMethod();
    }
}

new Derived().someOtherMethod();
// *
// Doesn't work because 'super.someMethod' is 'undefined'.

TypeScript 5.3 inspecte désormais de plus près les appels de la propriété accesses/method de super pour voir s'ils correspondent à des champs de classe. Si c'est le cas, une erreur de vérification de type se produit.

Indices d'incrustation interactifs pour les types

Les indices d'incrustation de TypeScript permettent désormais de sauter à la définition des types ! Cela facilite la navigation dans votre code.


Paramètres pour privilégier les auto-importations type

Auparavant, lorsque TypeScript générait des auto-importations pour quelque chose dans une position de type, il ajoutait un modificateur de type basé sur vos paramètres. Par exemple, lors de l'obtention d'un auto-import sur Person dans ce qui suit :

Code : Sélectionner tout
export let p: Person

l'expérience d'édition de TypeScript ajoutait généralement un import pour Person en tant que :

Code : Sélectionner tout
1
2
3
import { Person } from "./types";

export let p: Person

et sous certains paramètres comme verbatimModuleSyntax, il ajouterait le modificateur type :

Code : Sélectionner tout
1
2
3
import { type Person } from "./types";

export let p: Person

Cependant, il se peut que votre base de code ne soit pas en mesure d'utiliser certaines de ces options, ou que vous ayez simplement une préférence pour les importations type explicites lorsque c'est possible.

Grâce à une modification récente, TypeScript permet désormais de faire de cette option une option spécifique à l'éditeur. Dans Visual Studio Code, vous pouvez l'activer dans l'interface utilisateur sous "TypeScript > Preferences : Prefer Type Only Auto Imports", ou comme l'option de configuration JSON typescript.preferences.preferTypeOnlyAutoImports.

Optimisations en sautant l'analyse JSDoc

Lors de l'exécution de TypeScript via tsc, le compilateur évitera...
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.

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