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

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

TypeScript Discussion :

TypeScript 4.7 est disponible et apporte la prise en charge du module ECMAScript dans Node.js


Sujet :

TypeScript

  1. #1
    Chroniqueur Actualités

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Mars 2013
    Messages
    8 451
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Mars 2013
    Messages : 8 451
    Points : 197 705
    Points
    197 705
    Par défaut TypeScript 4.7 est disponible et apporte la prise en charge du module ECMAScript dans Node.js
    TypeScript 4.7 Beta s'accompagne de la prise en charge du module ECMAScript dans Node.js,
    et propose un contrôle de la détection de module

    Prise en charge du module ECMAScript dans Node.js

    Depuis quelques années, Node.js travaille pour supporter les modules ECMAScript (ESM). Cela a été une fonctionnalité très difficile à implémenter, car l'écosystème Node.js est construit sur un système de modules différent appelé CommonJS (CJS). L'interopérabilité entre les deux apporte de grands défis. Cependant, la prise en charge d'ESM dans Node.js a été largement implémentée dans Node.js 12 et versions ultérieures. Autour de TypeScript 4.5, Microsoft a déployé une prise en charge en nightly uniquement pour ESM dans Node.js afin d'obtenir des commentaires des utilisateurs et de permettre aux auteurs de bibliothèques de se préparer à une prise en charge plus large.

    TypeScript 4.7 ajoute cette fonctionnalité avec deux nouveaux paramètres de module : node12 et nodenext.

    Code JavaScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    {
        "compilerOptions": {
            "module": "nodenext",
        }
    }

    Ces nouveaux modes apportent quelques fonctionnalités de haut niveau que nous allons explorer ici.

    type dans package.json et les nouvelles extensions

    Node.js prend en charge un nouveau paramètre dans package.json appelé type. "type" peut être défini sur "module" ou "commonjs".

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    {
        "name": "my-package",
        "type": "module",
     
        "//": "...",
        "dependencies": {
        }
    }

    Ce paramètre contrôle si les fichiers .js sont interprétés comme des modules ES ou des modules CommonJS, et par défaut sur CommonJS lorsqu'il n'est pas défini. Lorsqu'un fichier est considéré comme un module ES, quelques règles différentes entrent en jeu par rapport à CommonJS*:
    • Les instructions d'importation/exportation (et l'attente de niveau supérieur dans nodenext) peuvent être utilisées.
    • Les chemins d'importation relatifs nécessitent des extensions complètes (nous devons écrire import "./foo.js" au lieu de import "./foo").
    • Les importations peuvent être résolues différemment des dépendances dans node_modules.
    • Certaines valeurs de type global telles que require() et process ne peuvent pas être utilisées directement.
    • Les modules CommonJS sont importés selon certaines règles spéciales.

    Pour superposer le fonctionnement de TypeScript dans ce système, les fichiers .ts et .tsx fonctionnent désormais de la même manière. Lorsque TypeScript trouve un fichier .ts, .tsx, .js ou .jsx, il recherche un package.json pour voir si ce fichier est un module ES et l'utilise pour déterminer*:
    • comment trouver d'autres modules que ce fichier importe
    • et comment transformer ce fichier s'il produit des sorties

    Lorsqu'un fichier .ts est compilé en tant que module ES, les instructions d'import/export ECMAScript sont laissées seules dans la sortie .js ; lorsqu'il est compilé en tant que module CommonJS, il produira la même sortie que vous obtenez aujourd'hui sous --module commonjs.

    Cela signifie également que les chemins se résolvent différemment entre les fichiers .ts qui sont des modules ES et ceux qui sont des modules CJS. Par exemple, supposons que vous ayez le code suivant aujourd'hui*:

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // ./foo.ts
    export function helper() {
        // ...
    }
     
    // ./bar.ts
    import { helper } from "./foo"; // only works in CJS
     
    helper();

    Ce code fonctionne dans les modules CommonJS, mais échouera dans les modules ES car les chemins d'importation relatifs doivent utiliser des extensions. En conséquence, il devra être réécrit pour utiliser l'extension de la sortie de foot.ts - donc bar.ts devra plutôt importer depuis ./foo.js.

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    // ./bar.ts
    import { helper } from "./foo.js"; // works in ESM & CJS
     
    helper();

    Cela peut sembler un peu lourd au début, mais les outils TypeScript tels que les importations automatiques et la saisie semi-automatique le feront généralement pour vous.

    Une autre chose à mentionner est le fait que cela s'applique également aux fichiers .d.ts. Lorsque TypeScript trouve un fichier .d.ts dans le package, il est interprété en fonction du package contenant.

    Nouvelles extensions de fichiers

    Le champ type dans package.json est agréable car il nous permet de continuer à utiliser les extensions de fichier .ts et .js, ce qui peut être pratique*; cependant, vous devrez parfois écrire un fichier qui diffère du type spécifié. Vous pourriez aussi préférer être toujours explicite.

    Node.js prend en charge deux extensions pour vous aider*: .mjs et .cjs. Les fichiers .mjs sont toujours des modules ES et les fichiers .cjs sont toujours des modules CommonJS, et il n'y a aucun moyen de les remplacer.

    À son tour, TypeScript prend en charge deux nouvelles extensions de fichier source*: .mts et .cts. Lorsque TypeScript les émet vers des fichiers JavaScript, il les émet vers .mjs et .cjs respectivement.

    De plus, TypeScript prend également en charge deux nouvelles extensions de fichier de déclaration : .d.mts et .d.cts. Lorsque TypeScript génère des fichiers de déclaration pour .mts et .cts, leurs extensions correspondantes seront .d.mts et .d.cts.

    L'utilisation de ces extensions est entièrement facultative, mais sera souvent utile même si vous choisissez de ne pas les utiliser dans le cadre de votre flux de travail principal.

    Nom : typescript.png
Affichages : 52302
Taille : 4,6 Ko

    Interopérabilité CommonJS

    Node.js permet aux modules ES d'importer des modules CommonJS comme s'il s'agissait de modules ES avec une exportation par défaut.

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // ./foo.cts
    export function helper() {
        console.log("hello world!");
    }
     
    // ./bar.mts
    import foo from "./foo.cjs";
     
    // prints "hello world!"
    foo.helper();

    Dans certains cas, Node.js synthétise également des exportations nommées à partir de modules CommonJS, ce qui peut être plus pratique. Dans ces cas, les modules ES peuvent utiliser une importation "de style espace de noms" (c'est-à-dire import * as foo from "...")) ou des importations nommées (c'est-à-dire import { helper } from "...")

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // ./foo.cts
    export function helper() {
        console.log("hello world!");
    }
     
    // ./bar.mts
    import { helper } from "./foo.cjs";
     
    // prints "hello world!"
    helper();

    Il n'y a pas toujours un moyen pour TypeScript de savoir si ces importations nommées seront synthétisées, mais TypeScript se trompera en étant permissif et utilisera certaines heuristiques lors de l'importation à partir d'un fichier qui est définitivement un module CommonJS.

    Une note spécifique à TypeScript concernant l'interopérabilité est la syntaxe suivante*:

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    import foo = require("foo");

    Dans un module CommonJS, cela se résume à un appel require() , et dans un module ES, cela importe createRequire pour obtenir la même chose. Cela rendra le code moins portable sur les runtimes comme le navigateur (qui ne prend pas en charge require()), mais sera souvent utile pour l'interopérabilité. À son tour, vous pouvez écrire l'exemple ci-dessus en utilisant cette syntaxe comme suit*:

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // ./foo.cts
    export function helper() {
        console.log("hello world!");
    }
     
    // ./bar.mts
    import foo = require("./foo.cjs");
     
    foo.helper()

    Enfin, il convient de noter que le seul moyen d'importer des fichiers ESM à partir d'un module CJS consiste à utiliser des appels dynamiques import(). Cela peut présenter des défis, mais c'est le comportement dans Node.js aujourd'hui.

    package.json Exportations, importations et auto-référencement

    Node.js prend en charge un nouveau champ pour définir les points d'entrée dans package.json appelé "exports". Ce champ est une alternative plus puissante à la définition de "main" dans package.json, et peut contrôler quelles parties de votre package sont exposées aux consommateurs.

    Voici un package.json qui prend en charge des points d'entrée séparés pour CommonJS et ESM*:

    Code TypeScript : 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
    // package.json
    {
        "name": "my-package",
        "type": "module",
        "exports": {
            ".": {
                // Entry-point for `import "my-package"` in ESM
                "import": "./esm/index.js",
     
                // Entry-point for `require("my-package") in CJS
                "require": "./commonjs/index.cjs",
            },
        },
     
        // CJS fall-back for older versions of Node.js
        "main": "./commonjs/index.cjs",
    }

    Avec la prise en charge de Node d'origine de TypeScript, il rechercherait un champ "main", puis rechercherait les fichiers de déclaration correspondant à cette entrée. Par exemple, si "main" pointe vers ./lib/index.js, TypeScript recherchera un fichier appelé ./lib/index.d.ts. Un auteur de package pourrait remplacer cela en spécifiant un champ séparé appelé "types" (par exemple "types": "./types/index.d.ts").

    Le nouveau support fonctionne de la même manière avec les conditions d'importation. Par défaut, TypeScript superpose les mêmes règles avec les conditions d'importation - si vous écrivez une importation à partir d'un module ES, il recherchera le champ d'importation et, à partir d'un module CommonJS, il examinera le champ requis. S'il les trouve, il cherchera un fichier de déclaration correspondant. Si vous devez pointer vers un emplacement différent pour vos déclarations de type, vous pouvez ajouter une condition d'importation "types".

    Code TypeScript : 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
    26
    27
    28
    29
    30
    31
    // package.json
    {
        "name": "my-package",
        "type": "module",
        "exports": {
            ".": {
                // Entry-point for `import "my-package"` in ESM
                "import": {
                    // Where TypeScript will look.
                    "types": "./types/esm/index.d.ts",
     
                    // Where Node.js will look.
                    "default": "./esm/index.js"
                },
                // Entry-point for `require("my-package") in CJS
                "require": {
                    // Where TypeScript will look.
                    "types": "./types/commonjs/index.d.cts",
     
                    // Where Node.js will look.
                    "default": "./commonjs/index.cjs"
                },
            }
        },
     
        // Fall-back for older versions of TypeScript
        "types": "./types/index.d.ts",
     
        // CJS fall-back for older versions of Node.js
        "main": "./commonjs/index.cjs"
    }

    Notez que la condition "types" doit toujours venir en premier dans "exports".

    TypeScript prend également en charge le champ "imports" de package.json de la même manière (recherche de fichiers de déclaration à côté des fichiers correspondants) et prend en charge les packages qui se référencent eux-mêmes. Ces fonctionnalités ne sont généralement pas aussi impliquées, mais sont prises en charge.

    Contrôle de la détection de module

    Un problème avec l'introduction des modules dans JavaScript était l'ambiguïté entre le code "script" existant et le nouveau code de module. Le code JavaScript dans un module s'exécute légèrement différemment et a des règles de portée différentes, de sorte que les outils doivent prendre des décisions sur la façon dont chaque fichier s'exécute. Par exemple, Node.js nécessite que les points d'entrée du module soient écrits dans un .mjs, ou qu'il ait un package.json à proximité avec "type": "module". TypeScript traite un fichier comme un module chaque fois qu'il trouve une instruction d'importation ou d'exportation dans un fichier, mais sinon, il supposera qu'un fichier .ts ou .js est un fichier de script agissant sur la portée globale.

    Cela ne correspond pas tout à fait au comportement de Node.js où le package.json peut modifier le format d'un fichier, ou le paramètre --jsx react-jsx, où tout fichier JSX contient une importation implicite vers une usine JSX. Cela ne correspond pas non plus aux attentes modernes où la plupart des nouveaux codes TypeScript sont écrits en pensant aux modules.

    C'est pourquoi TypeScript 4.7 introduit une nouvelle option appelée moduleDetection. moduleDetection peut prendre 3 valeurs : "auto" (la valeur par défaut), "legacy" (le même comportement que 4.6 et antérieur) et "force".

    En mode "auto", TypeScript recherchera non seulement les instructions d'importation et d'exportation, mais il vérifiera également si :
    • le champ "type" dans package.json est défini sur "module" lors de l'exécution sous --module nodenext/--module node12, et
    • vérifiera si le fichier actuel est un fichier JSX lors de l'exécution sous --jsx react-jsx

    Dans les cas où vous souhaitez que chaque fichier soit traité comme un module, le paramètre "forcer" garantit que chaque fichier sans déclaration est traité comme un module. Cela sera vrai quelle que soit la configuration de module, moduleResoluton et jsx.

    Pendant ce temps, l'option "héritée" revient simplement à l'ancien comportement consistant à rechercher uniquement les instructions d'importation et d'exportation pour déterminer si un fichier est un module.

    Source : TypeScript
    Contribuez au club : Corrections, suggestions, critiques, ... : Contactez le service news et Rédigez des actualités

  2. #2
    Chroniqueur Actualités

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Mars 2013
    Messages
    8 451
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Mars 2013
    Messages : 8 451
    Points : 197 705
    Points
    197 705
    Par défaut TypeScript 4.7 RC s'accompagne de la prise en charge du module ECMAScript dans Node.js
    TypeScript 4.7 RC s'accompagne de la prise en charge du module ECMAScript dans Node.js,
    et propose un contrôle de la détection de module

    Microsoft a annoncé la disponibilité de la RC (Release Candidate) de TypeScript 4.7 : « D'ici à la version stable de TypeScript 4.7, nous n'attendons aucun autre changement en dehors des corrections de bogues critiques ».

    Quoi de neuf depuis la bêta ?

    Après la version bêta, nous avons réalisé que typeof sur les champs #private avait des problèmes de compatibilité avec l'API. Nous nous sommes aussi demandé si typeof this.#somePrivate compose bien sur quelque chose de plus important : la déclaration émission. Par conséquent, la fonctionnalité ne sera pas dans TypeScript 4.7.

    Depuis la version bêta, la syntaxe du mode de résolution est toujours disponible pour les directives /// <reference types="..." />; cependant, nous avons reçu des commentaires sur import type et voulions reconsidérer les besoins et la conception de la fonctionnalité. À son tour resolution-mode n'est disponible qu'à titre expérimental dans import type dans les versions Nightly de TypeScript.

    Cette version inclut également une nouvelle commande d'éditeur d'aperçu pour Go to Source Definition. Cela peut être utile dans les cas où un ordinaire Go to Source Definition vous amènerait à un fichier de déclaration au lieu de la source JavaScript ou TypeScript réelle.

    Certaines modifications majeures depuis la version bêta, notamment les règles relatives aux contraintes de paramètres de type plus strictes dans strictNullChecks, ont été annulées. Malheureusement, certains changements apparemment inoffensifs ont introduit des règles plus strictes autour des spreads JSX et des génériques utilisés dans les chaînes de modèle, qui sont de nouvelles pauses depuis la version bêta.

    Nom : typescript.png
Affichages : 15349
Taille : 4,6 Ko

    Prise en charge du module ECMAScript dans Node.js

    Depuis quelques années, Node.js travaille pour supporter les modules ECMAScript (ESM). Cela a été une fonctionnalité très difficile à implémenter, car l'écosystème Node.js est construit sur un système de modules différent appelé CommonJS (CJS). L'interopérabilité entre les deux apporte de grands défis. Cependant, la prise en charge d'ESM dans Node.js a été largement implémentée dans Node.js 12 et versions ultérieures. Autour de TypeScript 4.5, Microsoft a déployé une prise en charge en nightly uniquement pour ESM dans Node.js afin d'obtenir des commentaires des utilisateurs et de permettre aux auteurs de bibliothèques de se préparer à une prise en charge plus large.

    TypeScript 4.7 ajoute cette fonctionnalité avec deux nouveaux paramètres de module : node16 et nodenext.

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    {
        "compilerOptions": {
            "module": "nodenext",
        }
    }

    Ces nouveaux modes apportent quelques fonctionnalités de haut niveau que nous allons explorer ici.

    type dans package.json et les nouvelles extensions

    Node.js prend en charge un nouveau paramètre dans package.json appelé type. "type" peut être défini sur "module" ou "commonjs".

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    {
        "name": "my-package",
        "type": "module",
     
        "//": "...",
        "dependencies": {
        }
    }

    Ce paramètre contrôle si les fichiers .js sont interprétés comme des modules ES ou des modules CommonJS, et par défaut sur CommonJS lorsqu'il n'est pas défini. Lorsqu'un fichier est considéré comme un module ES, quelques règles différentes entrent en jeu par rapport à CommonJS :
    • Les instructions d'importation/exportation (et l'attente de niveau supérieur dans nodenext) peuvent être utilisées.
    • Les chemins d'importation relatifs nécessitent des extensions complètes (nous devons écrire import "./foo.js" au lieu de import "./foo").
    • Les importations peuvent être résolues différemment des dépendances dans node_modules.
    • Certaines valeurs de type global telles que require() et process ne peuvent pas être utilisées directement.
    • Les modules CommonJS sont importés selon certaines règles spéciales.

    Pour superposer le fonctionnement de TypeScript dans ce système, les fichiers .ts et .tsx fonctionnent désormais de la même manière. Lorsque TypeScript trouve un fichier .ts, .tsx, .js ou .jsx, il recherche un package.json pour voir si ce fichier est un module ES et l'utilise pour déterminer :
    • comment trouver d'autres modules que ce fichier importe
    • et comment transformer ce fichier s'il produit des sorties

    Lorsqu'un fichier .ts est compilé en tant que module ES, les instructions d'import/export ECMAScript sont laissées seules dans la sortie .js ; lorsqu'il est compilé en tant que module CommonJS, il produira la même sortie que vous obtenez aujourd'hui sous --module commonjs.

    Cela signifie également que les chemins se résolvent différemment entre les fichiers .ts qui sont des modules ES et ceux qui sont des modules CJS. Par exemple, supposons que vous ayez le code suivant aujourd'hui :

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // ./foo.ts
    export function helper() {
        // ...
    }
     
    // ./bar.ts
    import { helper } from "./foo"; // only works in CJS
     
    helper();

    Ce code fonctionne dans les modules CommonJS, mais échouera dans les modules ES car les chemins d'importation relatifs doivent utiliser des extensions. En conséquence, il devra être réécrit pour utiliser l'extension de la sortie de foot.ts - donc bar.ts devra plutôt importer depuis ./foo.js.

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    // ./bar.ts
    import { helper } from "./foo.js"; // works in ESM & CJS
     
    helper();

    Cela peut sembler un peu lourd au début, mais les outils TypeScript tels que les importations automatiques et la saisie semi-automatique le feront généralement pour vous.

    Une autre chose à mentionner est le fait que cela s'applique également aux fichiers .d.ts. Lorsque TypeScript trouve un fichier .d.ts dans le package, il est interprété en fonction du package contenant.

    Nouvelles extensions de fichiers

    Le champ type dans package.json est agréable car il nous permet de continuer à utiliser les extensions de fichier .ts et .js, ce qui peut être pratique ; cependant, vous devrez parfois écrire un fichier qui diffère du type spécifié. Vous pourriez aussi préférer être toujours explicite.

    Node.js prend en charge deux extensions pour vous aider : .mjs et .cjs. Les fichiers .mjs sont toujours des modules ES et les fichiers .cjs sont toujours des modules CommonJS, et il n'y a aucun moyen de les remplacer.

    À son tour, TypeScript prend en charge deux nouvelles extensions de fichier source : .mts et .cts. Lorsque TypeScript les émet vers des fichiers JavaScript, il les émet vers .mjs et .cjs respectivement.

    De plus, TypeScript prend également en charge deux nouvelles extensions de fichier de déclaration : .d.mts et .d.cts. Lorsque TypeScript génère des fichiers de déclaration pour .mts et .cts, leurs extensions correspondantes seront .d.mts et .d.cts.

    L'utilisation de ces extensions est entièrement facultative, mais sera souvent utile même si vous choisissez de ne pas les utiliser dans le cadre de votre flux de travail principal.

    Interopérabilité CommonJS

    Node.js permet aux modules ES d'importer des modules CommonJS comme s'il s'agissait de modules ES avec une exportation par défaut.

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // ./foo.cts
    export function helper() {
        console.log("hello world!");
    }
     
    // ./bar.mts
    import foo from "./foo.cjs";
     
    // prints "hello world!"
    foo.helper();

    Dans certains cas, Node.js synthétise également des exportations nommées à partir de modules CommonJS, ce qui peut être plus pratique. Dans ces cas, les modules ES peuvent utiliser une importation "de style espace de noms" (c'est-à-dire import * as foo from "...")) ou des importations nommées (c'est-à-dire import { helper } from "...")

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // ./foo.cts
    export function helper() {
        console.log("hello world!");
    }
     
    // ./bar.mts
    import { helper } from "./foo.cjs";
     
    // prints "hello world!"
    helper();

    Il n'y a pas toujours un moyen pour TypeScript de savoir si ces importations nommées seront synthétisées, mais TypeScript se trompera en étant permissif et utilisera certaines heuristiques lors de l'importation à partir d'un fichier qui est définitivement un module CommonJS.

    Une note spécifique à TypeScript concernant l'interopérabilité est la syntaxe suivante :

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    import foo = require("foo");

    Dans un module CommonJS, cela se résume à un appel require() , et dans un module ES, cela importe createRequire pour obtenir la même chose. Cela rendra le code moins portable sur les runtimes comme le navigateur (qui ne prend pas en charge require()), mais sera souvent utile pour l'interopérabilité. À son tour, vous pouvez écrire l'exemple ci-dessus en utilisant cette syntaxe comme suit :

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // ./foo.cts
    export function helper() {
        console.log("hello world!");
    }
     
    // ./bar.mts
    import foo = require("./foo.cjs");
     
    foo.helper()

    Enfin, il convient de noter que le seul moyen d'importer des fichiers ESM à partir d'un module CJS consiste à utiliser des appels dynamiques import(). Cela peut présenter des défis, mais c'est le comportement dans Node.js aujourd'hui.

    package.json Exportations, importations et auto-référencement

    Node.js prend en charge un nouveau champ pour définir les points d'entrée dans package.json appelé "exports". Ce champ est une alternative plus puissante à la définition de "main" dans package.json, et peut contrôler quelles parties de votre package sont exposées aux consommateurs.

    Voici un package.json qui prend en charge des points d'entrée séparés pour CommonJS et ESM*:

    Code TypeScript : 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
    // package.json
    {
        "name": "my-package",
        "type": "module",
        "exports": {
            ".": {
                // Entry-point for `import "my-package"` in ESM
                "import": "./esm/index.js",
     
                // Entry-point for `require("my-package") in CJS
                "require": "./commonjs/index.cjs",
            },
        },
     
        // CJS fall-back for older versions of Node.js
        "main": "./commonjs/index.cjs",
    }

    Avec la prise en charge de Node d'origine de TypeScript, il rechercherait un champ "main", puis rechercherait les fichiers de déclaration correspondant à cette entrée. Par exemple, si "main" pointe vers ./lib/index.js, TypeScript recherchera un fichier appelé ./lib/index.d.ts. Un auteur de package pourrait remplacer cela en spécifiant un champ séparé appelé "types" (par exemple "types": "./types/index.d.ts").

    Le nouveau support fonctionne de la même manière avec les conditions d'importation. Par défaut, TypeScript superpose les mêmes règles avec les conditions d'importation - si vous écrivez une importation à partir d'un module ES, il recherchera le champ d'importation et, à partir d'un module CommonJS, il examinera le champ requis. S'il les trouve, il cherchera un fichier de déclaration correspondant. Si vous devez pointer vers un emplacement différent pour vos déclarations de type, vous pouvez ajouter une condition d'importation "types".

    Code TypeScript : 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
    26
    27
    28
    29
    30
    31
    // package.json
    {
        "name": "my-package",
        "type": "module",
        "exports": {
            ".": {
                // Entry-point for `import "my-package"` in ESM
                "import": {
                    // Where TypeScript will look.
                    "types": "./types/esm/index.d.ts",
     
                    // Where Node.js will look.
                    "default": "./esm/index.js"
                },
                // Entry-point for `require("my-package") in CJS
                "require": {
                    // Where TypeScript will look.
                    "types": "./types/commonjs/index.d.cts",
     
                    // Where Node.js will look.
                    "default": "./commonjs/index.cjs"
                },
            }
        },
     
        // Fall-back for older versions of TypeScript
        "types": "./types/index.d.ts",
     
        // CJS fall-back for older versions of Node.js
        "main": "./commonjs/index.cjs"
    }

    Notez que la condition "types" doit toujours venir en premier dans "exports".

    TypeScript prend également en charge le champ "imports" de package.json de la même manière (recherche de fichiers de déclaration à côté des fichiers correspondants) et prend en charge les packages qui se référencent eux-mêmes. Ces fonctionnalités ne sont généralement pas aussi impliquées, mais sont prises en charge.

    Contrôle de la détection de module

    Un problème avec l'introduction des modules dans JavaScript était l'ambiguïté entre le code "script" existant et le nouveau code de module. Le code JavaScript dans un module s'exécute légèrement différemment et a des règles de portée différentes, de sorte que les outils doivent prendre des décisions sur la façon dont chaque fichier s'exécute. Par exemple, Node.js nécessite que les points d'entrée du module soient écrits dans un .mjs, ou qu'il ait un package.json à proximité avec "type": "module". TypeScript traite un fichier comme un module chaque fois qu'il trouve une instruction d'importation ou d'exportation dans un fichier, mais sinon, il supposera qu'un fichier .ts ou .js est un fichier de script agissant sur la portée globale.

    Cela ne correspond pas tout à fait au comportement de Node.js où le package.json peut modifier le format d'un fichier, ou le paramètre --jsx react-jsx, où tout fichier JSX contient une importation implicite vers une usine JSX. Cela ne correspond pas non plus aux attentes modernes où la plupart des nouveaux codes TypeScript sont écrits en pensant aux modules.

    C'est pourquoi TypeScript 4.7 introduit une nouvelle option appelée moduleDetection. moduleDetection peut prendre 3 valeurs : "auto" (la valeur par défaut), "legacy" (le même comportement que 4.6 et antérieur) et "force".

    En mode "auto", TypeScript recherchera non seulement les instructions d'importation et d'exportation, mais il vérifiera également si :
    • le champ "type" dans package.json est défini sur "module" lors de l'exécution sous --module nodenext/--module node12, et
    • vérifiera si le fichier actuel est un fichier JSX lors de l'exécution sous --jsx react-jsx

    Dans les cas où vous souhaitez que chaque fichier soit traité comme un module, le paramètre "forcer" garantit que chaque fichier sans déclaration est traité comme un module. Cela sera vrai quelle que soit la configuration de module, moduleResoluton et jsx.

    Pendant ce temps, l'option "héritée" revient simplement à l'ancien comportement consistant à rechercher uniquement les instructions d'importation et d'exportation pour déterminer si un fichier est un module.

    Source : Microsoft
    Contribuez au club : Corrections, suggestions, critiques, ... : Contactez le service news et Rédigez des actualités

  3. #3
    Chroniqueur Actualités

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Mars 2013
    Messages
    8 451
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Mars 2013
    Messages : 8 451
    Points : 197 705
    Points
    197 705
    Par défaut TypeScript 4.7 est disponible et apporte la prise en charge du module ECMAScript dans Node.js
    TypeScript 4.7 est disponible et apporte la prise en charge du module ECMAScript dans Node.js,
    ainsi que de nouvelles extensions de fichiers

    Microsoft a annoncé la disponibilité TypeScript 4.7 :

    « Aujourd'hui, nous sommes ravis d'annoncer la disponibilité de TypeScript 4.7 !

    « Si vous n'êtes pas encore familier avec TypeScript, c'est un langage qui s'appuie sur JavaScript et ajoute une syntaxe pour les types. Les types aident à décrire les types de valeurs avec lesquelles vous travaillez et les types de fonctions que vous appelez. TypeScript peut utiliser ces informations pour vous aider à éviter les erreurs telles que les fautes de frappe, les arguments manquants ou l'oubli de vérifier null et undefined ! Mais cette vérification de type n'est pas la seule chose que fait TypeScript - il utilise les informations de ces types pour vous offrir une expérience d'édition incroyable, alimentant des éléments tels que la complétion de code, la définition, le changement de nom, etc. Si vous utilisez déjà JavaScript dans Visual Studio ou Visual Studio Code, vous avez déjà utilisé indirectement TypeScript*! »

    Quoi de neuf depuis la bêta ?

    Après la version bêta, nous avons réalisé que typeof sur les champs #private avait des problèmes de compatibilité avec l'API. Nous nous sommes aussi demandé si typeof this.#somePrivate compose bien sur quelque chose de plus important : la déclaration émission. Par conséquent, la fonctionnalité ne sera pas dans TypeScript 4.7.

    Depuis la version bêta, la syntaxe du mode de résolution est toujours disponible pour les directives /// <reference types="..." />; cependant, nous avons reçu des commentaires sur import type et voulions reconsidérer les besoins et la conception de la fonctionnalité. À son tour resolution-mode n'est disponible qu'à titre expérimental dans import type dans les versions Nightly de TypeScript.

    Cette version inclut également une nouvelle commande d'éditeur d'aperçu pour Go to Source Definition. Cela peut être utile dans les cas où un ordinaire Go to Source Definition vous amènerait à un fichier de déclaration au lieu de la source JavaScript ou TypeScript réelle.

    Certaines modifications majeures depuis la version bêta, notamment les règles relatives aux contraintes de paramètres de type plus strictes dans strictNullChecks, ont été annulées. Malheureusement, certains changements apparemment inoffensifs ont introduit des règles plus strictes autour des spreads JSX et des génériques utilisés dans les chaînes de modèle, qui sont de nouvelles pauses depuis la version bêta.

    Prise en charge du module ECMAScript dans Node.js

    Depuis quelques années, Node.js travaille pour supporter les modules ECMAScript (ESM). Cela a été une fonctionnalité très difficile à implémenter, car l'écosystème Node.js est construit sur un système de modules différent appelé CommonJS (CJS). L'interopérabilité entre les deux apporte de grands défis. Cependant, la prise en charge d'ESM dans Node.js a été largement implémentée dans Node.js 12 et versions ultérieures. Autour de TypeScript 4.5, Microsoft a déployé une prise en charge en nightly uniquement pour ESM dans Node.js afin d'obtenir des commentaires des utilisateurs et de permettre aux auteurs de bibliothèques de se préparer à une prise en charge plus large.

    TypeScript 4.7 ajoute cette fonctionnalité avec deux nouveaux paramètres de module : node12 et nodenext.

    Code JavaScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    {
        "compilerOptions": {
            "module": "nodenext",
        }
    }

    Ces nouveaux modes apportent quelques fonctionnalités de haut niveau que nous allons explorer ici.

    type dans package.json et les nouvelles extensions

    Node.js prend en charge un nouveau paramètre dans package.json appelé type. "type" peut être défini sur "module" ou "commonjs".

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    {
        "name": "my-package",
        "type": "module",
     
        "//": "...",
        "dependencies": {
        }
    }

    Ce paramètre contrôle si les fichiers .js sont interprétés comme des modules ES ou des modules CommonJS, et par défaut sur CommonJS lorsqu'il n'est pas défini. Lorsqu'un fichier est considéré comme un module ES, quelques règles différentes entrent en jeu par rapport à CommonJS*:
    • Les instructions d'importation/exportation (et l'attente de niveau supérieur dans nodenext) peuvent être utilisées.
    • Les chemins d'importation relatifs nécessitent des extensions complètes (nous devons écrire import "./foo.js" au lieu de import "./foo").
    • Les importations peuvent être résolues différemment des dépendances dans node_modules.
    • Certaines valeurs de type global telles que require() et process ne peuvent pas être utilisées directement.
    • Les modules CommonJS sont importés selon certaines règles spéciales.

    Pour superposer le fonctionnement de TypeScript dans ce système, les fichiers .ts et .tsx fonctionnent désormais de la même manière. Lorsque TypeScript trouve un fichier .ts, .tsx, .js ou .jsx, il recherche un package.json pour voir si ce fichier est un module ES et l'utilise pour déterminer :
    • comment trouver d'autres modules que ce fichier importe
    • et comment transformer ce fichier s'il produit des sorties

    Lorsqu'un fichier .ts est compilé en tant que module ES, les instructions d'import/export ECMAScript sont laissées seules dans la sortie .js ; lorsqu'il est compilé en tant que module CommonJS, il produira la même sortie que vous obtenez aujourd'hui sous --module commonjs.

    Cela signifie également que les chemins se résolvent différemment entre les fichiers .ts qui sont des modules ES et ceux qui sont des modules CJS. Par exemple, supposons que vous ayez le code suivant aujourd'hui*:

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // ./foo.ts
    export function helper() {
        // ...
    }
     
    // ./bar.ts
    import { helper } from "./foo"; // only works in CJS
     
    helper();

    Ce code fonctionne dans les modules CommonJS, mais échouera dans les modules ES car les chemins d'importation relatifs doivent utiliser des extensions. En conséquence, il devra être réécrit pour utiliser l'extension de la sortie de foot.ts - donc bar.ts devra plutôt importer depuis ./foo.js.

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    // ./bar.ts
    import { helper } from "./foo.js"; // works in ESM & CJS
     
    helper();

    Cela peut sembler un peu lourd au début, mais les outils TypeScript tels que les importations automatiques et la saisie semi-automatique le feront généralement pour vous.

    Une autre chose à mentionner est le fait que cela s'applique également aux fichiers .d.ts. Lorsque TypeScript trouve un fichier .d.ts dans le package, il est interprété en fonction du package contenant.

    Nom : typescript.png
Affichages : 6560
Taille : 4,6 Ko

    Nouvelles extensions de fichiers

    Le champ type dans package.json est agréable car il nous permet de continuer à utiliser les extensions de fichier .ts et .js, ce qui peut être pratique*; cependant, vous devrez parfois écrire un fichier qui diffère du type spécifié. Vous pourriez aussi préférer être toujours explicite.

    Node.js prend en charge deux extensions pour vous aider*: .mjs et .cjs. Les fichiers .mjs sont toujours des modules ES et les fichiers .cjs sont toujours des modules CommonJS, et il n'y a aucun moyen de les remplacer.

    À son tour, TypeScript prend en charge deux nouvelles extensions de fichier source*: .mts et .cts. Lorsque TypeScript les émet vers des fichiers JavaScript, il les émet vers .mjs et .cjs respectivement.

    De plus, TypeScript prend également en charge deux nouvelles extensions de fichier de déclaration : .d.mts et .d.cts. Lorsque TypeScript génère des fichiers de déclaration pour .mts et .cts, leurs extensions correspondantes seront .d.mts et .d.cts.

    L'utilisation de ces extensions est entièrement facultative, mais sera souvent utile même si vous choisissez de ne pas les utiliser dans le cadre de votre flux de travail principal.

    Interopérabilité CommonJS

    Node.js permet aux modules ES d'importer des modules CommonJS comme s'il s'agissait de modules ES avec une exportation par défaut.

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // ./foo.cts
    export function helper() {
        console.log("hello world!");
    }
     
    // ./bar.mts
    import foo from "./foo.cjs";
     
    // prints "hello world!"
    foo.helper();

    Dans certains cas, Node.js synthétise également des exportations nommées à partir de modules CommonJS, ce qui peut être plus pratique. Dans ces cas, les modules ES peuvent utiliser une importation "de style espace de noms" (c'est-à-dire import * as foo from "...")) ou des importations nommées (c'est-à-dire import { helper } from "...")

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // ./foo.cts
    export function helper() {
        console.log("hello world!");
    }
     
    // ./bar.mts
    import { helper } from "./foo.cjs";
     
    // prints "hello world!"
    helper();

    Il n'y a pas toujours un moyen pour TypeScript de savoir si ces importations nommées seront synthétisées, mais TypeScript se trompera en étant permissif et utilisera certaines heuristiques lors de l'importation à partir d'un fichier qui est définitivement un module CommonJS.

    Une note spécifique à TypeScript concernant l'interopérabilité est la syntaxe suivante :

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    import foo = require("foo");

    Dans un module CommonJS, cela se résume à un appel require() , et dans un module ES, cela importe createRequire pour obtenir la même chose. Cela rendra le code moins portable sur les runtimes comme le navigateur (qui ne prend pas en charge require()), mais sera souvent utile pour l'interopérabilité. À son tour, vous pouvez écrire l'exemple ci-dessus en utilisant cette syntaxe comme suit :

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // ./foo.cts
    export function helper() {
        console.log("hello world!");
    }
     
    // ./bar.mts
    import foo = require("./foo.cjs");
     
    foo.helper()

    Enfin, il convient de noter que le seul moyen d'importer des fichiers ESM à partir d'un module CJS consiste à utiliser des appels dynamiques import(). Cela peut présenter des défis, mais c'est le comportement dans Node.js aujourd'hui.

    package.json Exportations, importations et auto-référencement

    Node.js prend en charge un nouveau champ pour définir les points d'entrée dans package.json appelé "exports". Ce champ est une alternative plus puissante à la définition de "main" dans package.json, et peut contrôler quelles parties de votre package sont exposées aux consommateurs.

    Voici un package.json qui prend en charge des points d'entrée séparés pour CommonJS et ESM :

    Code TypeScript : 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
    // package.json
    {
        "name": "my-package",
        "type": "module",
        "exports": {
            ".": {
                // Entry-point for `import "my-package"` in ESM
                "import": "./esm/index.js",
     
                // Entry-point for `require("my-package") in CJS
                "require": "./commonjs/index.cjs",
            },
        },
     
        // CJS fall-back for older versions of Node.js
        "main": "./commonjs/index.cjs",
    }

    Avec la prise en charge de Node d'origine de TypeScript, il rechercherait un champ "main", puis rechercherait les fichiers de déclaration correspondant à cette entrée. Par exemple, si "main" pointe vers ./lib/index.js, TypeScript recherchera un fichier appelé ./lib/index.d.ts. Un auteur de package pourrait remplacer cela en spécifiant un champ séparé appelé "types" (par exemple "types": "./types/index.d.ts").

    Le nouveau support fonctionne de la même manière avec les conditions d'importation. Par défaut, TypeScript superpose les mêmes règles avec les conditions d'importation - si vous écrivez une importation à partir d'un module ES, il recherchera le champ d'importation et, à partir d'un module CommonJS, il examinera le champ requis. S'il les trouve, il cherchera un fichier de déclaration correspondant. Si vous devez pointer vers un emplacement différent pour vos déclarations de type, vous pouvez ajouter une condition d'importation "types".

    Code TypeScript : 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
    26
    27
    28
    29
    30
    31
    // package.json
    {
        "name": "my-package",
        "type": "module",
        "exports": {
            ".": {
                // Entry-point for `import "my-package"` in ESM
                "import": {
                    // Where TypeScript will look.
                    "types": "./types/esm/index.d.ts",
     
                    // Where Node.js will look.
                    "default": "./esm/index.js"
                },
                // Entry-point for `require("my-package") in CJS
                "require": {
                    // Where TypeScript will look.
                    "types": "./types/commonjs/index.d.cts",
     
                    // Where Node.js will look.
                    "default": "./commonjs/index.cjs"
                },
            }
        },
     
        // Fall-back for older versions of TypeScript
        "types": "./types/index.d.ts",
     
        // CJS fall-back for older versions of Node.js
        "main": "./commonjs/index.cjs"
    }

    Notez que la condition "types" doit toujours venir en premier dans "exports".

    TypeScript prend également en charge le champ "imports" de package.json de la même manière (recherche de fichiers de déclaration à côté des fichiers correspondants) et prend en charge les packages qui se référencent eux-mêmes. Ces fonctionnalités ne sont généralement pas aussi impliquées, mais sont prises en charge.

    Contrôle de la détection de module

    Un problème avec l'introduction des modules dans JavaScript était l'ambiguïté entre le code "script" existant et le nouveau code de module. Le code JavaScript dans un module s'exécute légèrement différemment et a des règles de portée différentes, de sorte que les outils doivent prendre des décisions sur la façon dont chaque fichier s'exécute. Par exemple, Node.js nécessite que les points d'entrée du module soient écrits dans un .mjs, ou qu'il ait un package.json à proximité avec "type": "module". TypeScript traite un fichier comme un module chaque fois qu'il trouve une instruction d'importation ou d'exportation dans un fichier, mais sinon, il supposera qu'un fichier .ts ou .js est un fichier de script agissant sur la portée globale.

    Cela ne correspond pas tout à fait au comportement de Node.js où le package.json peut modifier le format d'un fichier, ou le paramètre --jsx react-jsx, où tout fichier JSX contient une importation implicite vers une usine JSX. Cela ne correspond pas non plus aux attentes modernes où la plupart des nouveaux codes TypeScript sont écrits en pensant aux modules.

    C'est pourquoi TypeScript 4.7 introduit une nouvelle option appelée moduleDetection. moduleDetection peut prendre 3 valeurs : "auto" (la valeur par défaut), "legacy" (le même comportement que 4.6 et antérieur) et "force".

    En mode "auto", TypeScript recherchera non seulement les instructions d'importation et d'exportation, mais il vérifiera également si :
    • le champ "type" dans package.json est défini sur "module" lors de l'exécution sous --module nodenext/--module node12, et
    • vérifiera si le fichier actuel est un fichier JSX lors de l'exécution sous --jsx react-jsx

    Dans les cas où vous souhaitez que chaque fichier soit traité comme un module, le paramètre "forcer" garantit que chaque fichier sans déclaration est traité comme un module. Cela sera vrai quelle que soit la configuration de module, moduleResoluton et jsx.

    Pendant ce temps, l'option "héritée" revient simplement à l'ancien comportement consistant à rechercher uniquement les instructions d'importation et d'exportation pour déterminer si un fichier est un module.

    Source : TypeScript
    Contribuez au club : Corrections, suggestions, critiques, ... : Contactez le service news et Rédigez des actualités

Discussions similaires

  1. Réponses: 3
    Dernier message: 17/08/2021, 09h17
  2. Réponses: 0
    Dernier message: 23/11/2020, 14h45
  3. Réponses: 1
    Dernier message: 08/10/2020, 22h20
  4. Réponses: 0
    Dernier message: 28/03/2018, 00h20
  5. Réponses: 0
    Dernier message: 23/02/2017, 12h12

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