Cómo utilizar módulos en TypeScript

Índice
  1. Introducción
  • Prerrequisitos
  • Configuración del proyecto
  • Creación de módulos en TypeScript conexport
  • Uso de módulos en TypeScript conimport
  • Uso de exportaciones predeterminadas
  • Uso export =y import = require()compatibilidad
  • Conclusión
  • El autor seleccionó el Fondo de Ayuda COVID-19 para recibir una donación como parte del programa Write for DOnations .

    Introducción

    Los módulos son una forma de organizar el código en piezas más pequeñas y manejables, lo que permite que los programas importen código desde diferentes partes de la aplicación. Ha habido algunas estrategias para implementar la modularidad en el código JavaScript a lo largo de los años. TypeScript evolucionó junto con las especificaciones ECMAScript para proporcionar un sistema de módulos estándar para programas JavaScript que tenga la flexibilidad de trabajar con estos diferentes formatos. TypeScript ofrece soporte para crear y usar módulos con una sintaxis unificada que es similar a la sintaxis del módulo ES , al tiempo que permite al desarrollador generar código que se dirige a diferentes cargadores de módulos, como Node.js ( CommonJS ), require.js ( AMD ), UMD , SystemJS o módulos nativos ECMAScript 2015 (ES6).

    En este tutorial, creará y utilizará módulos en TypeScript. Seguirá diferentes ejemplos de código en su propio entorno TypeScript, mostrando cómo usar la palabra clave importand export, cómo establecer exportaciones predeterminadas y cómo hacer que los archivos con exportsobjetos sobrescritos sean compatibles con su código.

    Prerrequisitos

    Para seguir este tutorial, necesitarás:

    • Un entorno en el que puede ejecutar programas TypeScript para seguir los ejemplos. Para configurarlo en su máquina local, necesitará lo siguiente:
      • Se instalaron Node y npm (o yarn ) para ejecutar un entorno de desarrollo que maneje paquetes relacionados con TypeScript. Este tutorial se probó con la versión 14.3.0 de Node.js y la versión 6.14.5 de npm. Para instalar en macOS o Ubuntu 18.04, siga los pasos de Cómo instalar Node.js y crear un entorno de desarrollo local en macOS o la sección Instalación mediante un PPA de Cómo instalar Node.js en Ubuntu 18.04 . Esto también funciona si está utilizando el Subsistema de Windows para Linux (WSL) .
    • Necesitará conocimientos suficientes de JavaScript, especialmente de sintaxis ES6+, como desestructuración, operadores rest e importaciones/exportaciones . Si necesita más información sobre estos temas, le recomendamos leer nuestra serie Cómo codificar en JavaScript .
    • Este tutorial hará referencia a aspectos de los editores de texto que admiten TypeScript y muestran errores en línea. Esto no es necesario para usar TypeScript, pero aprovecha más las características de TypeScript. Para aprovecharlas, puede usar un editor de texto como Visual Studio Code , que tiene compatibilidad total con TypeScript de fábrica.

    Todos los ejemplos que se muestran en este tutorial se crearon utilizando TypeScript versión 4.2.2.

    Configuración del proyecto

    En este paso, creará un proyecto de muestra que contiene dos clases pequeñas para manejar operaciones vectoriales: Vector2y Vector3. En este caso, un vector se refiere a una medida matemática de magnitud y distancia, que se utiliza a menudo en programas de gráficos visuales.

    Las clases que cree tendrán una única operación en cada una: la suma de vectores. Más adelante, utilizará estas clases de ejemplo para probar la importación y exportación de código de un programa a otro.

    Primero, crea un directorio que albergará tu código de muestra:

    1. mkdir vector_project

    Una vez creado el directorio, conviértalo en su directorio de trabajo:

    1. cd vector_project

    Ahora que estás en la raíz de tu proyecto, crea tu aplicación Node.js con npm:

    1. npm init

    Esto creará un package.jsonarchivo para su proyecto.

    A continuación, agregue TypeScript como una dependencia de desarrollo:

    1. npm install typescript@4.2.2 --save-dev

    Esto instalará TypeScript en su proyecto, con el compilador TypeScript configurado con su configuración predeterminada. Para crear sus propias configuraciones personalizadas, deberá crear un archivo de configuración específico.

    Cree y abra un archivo con el nombre tsconfig.jsonen la raíz de su proyecto. Para que su proyecto funcione con los ejercicios de este tutorial, agregue el siguiente contenido al archivo:

    tsconfig.json

    {  "compilerOptions": {    "target": "ES6",    "module": "CommonJS",    "outDir": "./out",    "rootDir": "./src",    "strict": true  }}

    En este código, se establecen varias configuraciones para el compilador TypeScript. "target": "ES6"determina el entorno para el que se compilará el código y "outDir": "./out"especifica "rootDir": "./src"qué directorios contendrán la salida y la entrada del compilador, respectivamente. "strict": trueestablece un nivel de verificación de tipos estricta. Por último, "module": "CommonJS"especifica el módulo system como CommonJS. Lo usará para simular el trabajo con una aplicación Node.js.

    Una vez configurado el proyecto, ahora puedes pasar a crear módulos con sintaxis básica.

    Creación de módulos en TypeScript conexport

    En esta sección, creará módulos en TypeScript utilizando la sintaxis de módulo de TypeScript.

    De manera predeterminada, los archivos en TypeScript se tratan como scripts globales. Esto significa que cualquier variable , clase , función u otra construcción declarada en el archivo está disponible globalmente. Tan pronto como comience a usar módulos en un archivo, este archivo pasa a tener alcance de módulo y ya no se ejecuta globalmente.

    Para mostrar esto en acción, creará su primera clase: Vector2. Cree un nuevo directorio llamado src/en la raíz del proyecto:

    1. mkdir src

    Este es el directorio que usted establece como directorio raíz ( rootDir) en su tsconfig.jsonarchivo.

    Dentro de esta carpeta, crea un nuevo archivo llamado vector2.ts. Abre este archivo en tu editor de texto favorito y luego escribe tu Vector2clase:

    proyecto_vector/src/vector2.ts

    class Vector2 {  constructor(public x: number, public y: number) {}  add(otherVector2: Vector2) {    return new Vector2(this.x + otherVector2.x, this.y + otherVector2.y);  }}

    En este código, estás declarando una clase llamada Vector2, que se crea al pasar dos números como parámetros, establecidos como propiedades xy y. Esta clase tiene un método que agrega un vector a sí misma al combinar los valores respectivos xde y y.

    Como su archivo actualmente no utiliza módulos, su Vector2alcance es global. Para convertir su archivo en un módulo, solo tiene que exportar su Vector2clase:

    proyecto_vector/src/vector2.ts

    export class Vector2 {  constructor(public x: number, public y: number) {}  add(otherVector2: Vector2) {    return new Vector2(this.x + otherVector2.x, this.y + otherVector2.y);  }}

    El archivo src/vector2.tsahora es un módulo que tiene una única exportación: la Vector2clase. Guarde y cierre el archivo.

    A continuación, puedes crear tu Vector3clase. Crea el vector3.tsarchivo dentro del src/directorio, luego abre el archivo en tu editor de texto favorito y escribe el siguiente código:

    proyecto_vector/src/vector3.ts

    export class Vector3 {  constructor(public x: number, public y: number, public z: number) {}  add(otherVector3: Vector3) {    return new Vector3(      this.x + otherVector3.x,      this.y + otherVector3.y,      this.z + otherVector3.z    );  }}

    Este código crea una clase similar a Vector2, pero con una zpropiedad adicional que almacena el vector en tres dimensiones. Observe que la exportpalabra clave ya ha convertido a este archivo en su propio módulo. Guarde y cierre este archivo.

    Ahora tienes dos archivos vector2.tsy vector3.ts, ambos son módulos. Cada archivo tiene una única exportación, que es la clase del vector que representan. En la siguiente sección, incorporarás estos módulos a otros archivos con importinstrucciones.

    Uso de módulos en TypeScript conimport

    En la sección anterior, viste cómo crear módulos. En esta sección, importarás estos módulos para usarlos en otras partes de tu código.

    Un escenario común al trabajar con módulos en TypeScript es tener un solo archivo que recopila varios módulos y los reexporta como un solo módulo. Para demostrar esto, cree un archivo llamado vectors.tsdentro de su src/directorio, luego abra este archivo en su editor favorito y escriba lo siguiente:

    proyecto_vectorial/src/vectors.ts

    import { Vector2 } from "./vector2";import { Vector3 } from "./vector3";

    Para importar otro módulo disponible en su proyecto, utilice la ruta relativa al archivo en una importdeclaración. En este caso, está importando ambos módulos desde ./vector2y ./vector3, que son las rutas relativas desde el archivo actual a los archivos src/vector2.tsy src/vector3.ts.

    Ahora que ha importado los vectores, puede volver a exportarlos en un solo módulo con la siguiente sintaxis resaltada:

    proyecto_vectorial/src/vectors.ts

    import { Vector2 } from "./vector2";import { Vector3 } from "./vector3";export { Vector2, Vector3 };

    La export {}sintaxis permite exportar varios identificadores. En este caso, se exportan las clases Vector2y Vector3mediante una única exportdeclaración.

    También puedes utilizar dos exportdeclaraciones separadas, como ésta:

    proyecto_vectorial/src/vectors.ts

    import { Vector2 } from "./vector2";import { Vector3 } from "./vector3";export { Vector2 };export { Vector3 };

    Esto tiene el mismo significado que el fragmento de código anterior.

    Dado que src/vectors.tssolo está importando dos clases para reexportarlas más tarde, puede utilizar una forma aún más breve de la sintaxis:

    proyecto_vectorial/src/vectors.ts

    export { Vector2 } from "./vector2";export { Vector3 } from "./vector3";

    La importdeclaración está implícita aquí y el compilador TypeScript la incluirá automáticamente. Luego, los archivos se exportarán inmediatamente con el mismo nombre. Guarde este archivo.

    Ahora que está exportando sus dos clases vectoriales desde el src/vectors.tsarchivo, cree un nuevo archivo llamado src/index.ts, luego abra el archivo y escriba el siguiente código:

    proyecto_vector/src/index.ts

    import { Vector2, Vector3 } from "./vectors";const vec2a = new Vector2(1, 2);const vec2b = new Vector2(2, 1);console.log(vec2a.add(vec2b));const vec3a = new Vector3(1, 2, 3);const vec3b = new Vector3(3, 2, 1);console.log(vec3a.add(vec3b));

    En este código, estás importando ambas clases de vector desde el src/vectors.tsarchivo, que utiliza la ruta relativa ./vectors. Luego, estás creando algunas instancias de vector, utilizando el addmétodo para sumarlas y luego registrando los resultados.

    Al importar exportaciones con nombre, también puede utilizar un alias diferente, lo que puede resultar útil para evitar conflictos de nombres dentro de un archivo. Para probar esto, realice los siguientes cambios resaltados en su archivo:

    proyecto_vector/src/index.ts

    import { Vector2 as Vec2, Vector3 as Vec3 } from "./vectors";const vec2a = new Vec2(1, 2);const vec2b = new Vec2(2, 1);console.log(vec2a.add(vec2b));const vec3a = new Vec3(1, 2, 3);const vec3b = new Vec3(3, 2, 1);console.log(vec3a.add(vec3b));

    Aquí se utiliza la aspalabra clave para establecer los alias Vec2y Vec3para las clases importadas.

    Observa cómo estás importando todo lo que está disponible dentro de ./vectors. Este archivo solo exporta esas dos clases, por lo que puedes usar la siguiente sintaxis para importar todo en una sola variable:

    proyecto_vector/src/index.ts

    import * as vectors from "./vectors";const vec2a = new vectors.Vector2(1, 2);const vec2b = new vectors.Vector2(2, 1);console.log(vec2a.add(vec2b));const vec3a = new vectors.Vector3(1, 2, 3);const vec3b = new vectors.Vector3(3, 2, 1);console.log(vec3a.add(vec3b));

    En el código resaltado arriba, se utiliza la import * assintaxis para importar todo lo que exporta un módulo en una única variable. También se tuvo que cambiar la forma en que se utilizaban las clases Vector2y Vector3, ya que ahora están disponibles dentro del vectorsobjeto, que se crea durante la importación.

    Si guarda el archivo y compila el proyecto usando tsc:

    1. npx tsc

    El compilador TypeScript creará el out/directorio (dada la compileOptions.outDiropción que configure en el tsconfig.jsonarchivo) y luego completará el directorio con archivos JavaScript.

    Abra el archivo compilado disponible out/index.jsen su editor de texto favorito. Se verá así:

    proyecto_vector/out/index.js

    "use strict";Object.defineProperty(exports, "__esModule", { value: true });const vectors = require("./vectors");const vec2a = new vectors.Vector2(1, 2);const vec2b = new vectors.Vector2(2, 1);console.log(vec2a.add(vec2b));const vec3a = new vectors.Vector3(1, 2, 3);const vec3b = new vectors.Vector3(3, 2, 1);console.log(vec3a.add(vec3b));

    Como la compilerOptions.moduleopción en el tsconfig.jsonarchivo está configurada en CommonJS, el compilador TypeScript crea código compatible con el sistema de módulos Node.js. Esto utiliza la requirefunción para cargar otros archivos como módulos.

    A continuación, eche un vistazo al src/vectors.tsarchivo compilado, que está disponible en out/vectors.js:

    proyecto_vectorial/out/vectors.js

    "use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.Vector3 = exports.Vector2 = void 0;var vector2_1 = require("./vector2");Object.defineProperty(exports, "Vector2", { enumerable: true, get: function () { return vector2_1.Vector2; } });var vector3_1 = require("./vector3");Object.defineProperty(exports, "Vector3", { enumerable: true, get: function () { return vector3_1.Vector3; } });

    Aquí, el compilador TypeScript creó un código compatible con la forma en que se exportan los módulos cuando se usa CommonJS, que es asignar los valores exportados al exportsobjeto.

    Ahora que ha probado la sintaxis para importar y exportar archivos y luego ha visto cómo se compilan en JavaScript, puede pasar a declarar exportaciones predeterminadas en su archivo.

    Uso de exportaciones predeterminadas

    En esta sección, examinará otra forma de exportar un valor desde un módulo denominada exportación predeterminada, que establece una exportación específica como la importación asumida desde un módulo. Esto puede simplificar el código cuando importe los archivos.

    Abra el src/vector2.tsarchivo nuevamente:

    proyecto_vector/src/vector2.ts

    export class Vector2 {  constructor(public x: number, public y: number) {}  add(otherVector2: Vector2) {    return new Vector2(this.x + otherVector2.x, this.y + otherVector2.y);  }}

    Observa cómo estás exportando un único valor desde tu archivo/módulo. Otra forma en la que podrías haber escrito tu exportación era utilizando una exportación predeterminada. Cada archivo puede tener como máximo una única exportación predeterminada, por lo que esto podría resultar útil en este caso.

    Para cambiar su exportación a una exportación predeterminada, agregue el siguiente código resaltado:

    proyecto_vector/src/vector2.ts

    export default class Vector2 {  constructor(public x: number, public y: number) {}  add(otherVector2: Vector2) {    return new Vector2(this.x + otherVector2.x, this.y + otherVector2.y);  }}

    Guarde el archivo y luego haga lo mismo en el src/vector3.tsarchivo:

    proyecto_vector/src/vector3.ts

    export default class Vector3 {  constructor(public x: number, public y: number, public z: number) {}  add(otherVector3: Vector3) {    return new Vector3(      this.x + otherVector3.x,      this.y + otherVector3.y,      this.z + otherVector3.z    );  }}

    Para importar sus exportaciones predeterminadas, guarde sus archivos, luego abra el src/vectors.tsarchivo y cambie su contenido a lo siguiente:

    proyecto_vectorial/src/vectors.ts

    import Vector2 from "./vector2";import Vector3 from "./vector3";export { Vector2, Vector3 };

    Tenga en cuenta que, en ambas importaciones, solo le está dando un nombre a su importación, en lugar de tener que usar la desestructuración para importar un valor específico. Esto importará automáticamente la exportación predeterminada de cada módulo.

    Cada módulo que tiene una exportación predeterminada también tiene una exportación especial llamada default, que se puede usar para acceder al valor exportado predeterminado. Para usar la export ... fromsintaxis abreviada que usaba antes, puede usar esa exportación denominada:

    proyecto_vectorial/src/vectors.ts

    export { default as Vector2 } from "./vector2";export { default as Vector3 } from "./vector3";

    Ahora estás reexportando la exportación predeterminada de cada módulo con un nombre específico.

    Uso export =y import = require()compatibilidad

    Algunos cargadores de módulos, como AMD y CommonJS, tienen un objeto llamado exportsque contiene todos los valores exportados por un módulo. Al utilizar cualquiera de esos cargadores de módulos, es posible sobrescribir el objeto exportado modificando el valor del exportsobjeto. Esto es similar a las exportaciones predeterminadas disponibles en los módulos ES y, por lo tanto, también en TypeScript. Sin embargo, estas dos sintaxis son incompatibles. En esta sección, veremos cómo TypeScript maneja este comportamiento de una manera compatible con las exportaciones predeterminadas.

    En TypeScript, cuando se utiliza un cargador de módulos que admite la sobrescritura del objeto exportado, se puede cambiar el valor del objeto exportado mediante la export = sintaxis. Para ello, se asigna el valor del objeto exportado al exportidentificador. Si se ha utilizado Node.js en el pasado, esto es lo mismo que utilizar exports = .

    Nota: asegúrese de que la opción compilerOptions.moduleen su tsconfig.jsonarchivo esté configurada CommonJSantes de realizar cualquiera de los siguientes cambios.

    Imagina que quieres cambiar el objeto exportado en cada uno de tus archivos vectoriales para que apunte a la clase vectorial en sí. Abre el archivo src/vector2.ts. Para cambiar el valor del objeto exportado en sí, realiza el siguiente cambio resaltado:

    proyecto_vector/src/vector2.ts

    export = class Vector2 {  constructor(public x: number, public y: number) {}  add(otherVector2: Vector2) {    return new Vector2(this.x + otherVector2.x, this.y + otherVector2.y);  }};

    Guarde esto y luego haga lo mismo con el archivo src/vector3.ts:

    proyecto_vector/src/vector3.ts

    export = class Vector3 {  constructor(public x: number, public y: number, public z: number) {}  add(otherVector3: Vector3) {    return new Vector3(      this.x + otherVector3.x,      this.y + otherVector3.y,      this.z + otherVector3.z    );  }};

    Por último, cambia tu vectors.tsespalda a la siguiente forma:

    proyecto_vectorial/src/vectors.ts

    import Vector2 from "./vector2";import Vector3 from "./vector3";export { Vector2, Vector3 };

    Guarde estos archivos y luego ejecute el compilador TypeScript:

    1. npx tsc

    El compilador de TypeScript le generará varios errores, incluidos los siguientes:

    Outputsrc/vectors.ts:1:8 - error TS1259: Module '"~/project/src/vector2"' can only be default-imported using the 'esModuleInterop' flag1 import Vector2 from "./vector2";         ~~~~~~~  src/vector2.ts:1:1      1 export = class Vector2 {        ~~~~~~~~~~~~~~~~~~~~~~~~      2   constructor(public x: number, public y: number) {}        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~    ...       6   }        ~~~      7 }        ~    This module is declared with using 'export =', and can only be used with a default import when using the 'esModuleInterop' flag.src/vectors.ts:2:8 - error TS1259: Module '"~/project/src/vector3"' can only be default-imported using the 'esModuleInterop' flag2 import Vector3 from "./vector3";         ~~~~~~~  src/vector3.ts:1:1      1 export = class Vector3 {        ~~~~~~~~~~~~~~~~~~~~~~~~      2   constructor(public x: number, public y: number, public z: number) {}        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~    ...      10   }        ~~~     11 }        ~    This module is declared with using 'export =', and can only be used with a default import when using the 'esModuleInterop' flag.

    Este error se debe a la forma en que estás importando tus archivos vectoriales dentro de src/vectors.ts. Este archivo aún usa la sintaxis para importar la exportación predeterminada de un módulo, pero ahora estás sobrescribiendo el objeto exportado, por lo que ya no tienes una exportación predeterminada. Usar ambas sintaxis juntas es incompatible.

    Hay dos formas de resolver esto: usando import = require()y configurando la esModuleInteroppropiedad trueen el archivo de configuración del compilador TypeScript.

    Primero, probará la sintaxis correcta para importar este tipo de módulo realizando el siguiente cambio resaltado en su código en el src/vectors.tsarchivo:

    proyecto_vectorial/src/vectors.ts

    import Vector2 = require("./vector2");import Vector3 = require("./vector3");export { Vector2, Vector3 };

    La import = require()sintaxis utiliza el exportsobjeto como valor para la importación en sí, lo que le permite utilizar cada clase de vector. La compilación de su código funcionará ahora como se esperaba.

    Otro enfoque para resolver el error de TypeScript 1259es establecer la opción compilerOptions.esModuleInteropen trueen el tsconfig.jsonarchivo. De manera predeterminada, este valor es false. Cuando se establece en true, el compilador de TypeScript emitirá JavaScript adicional que verifica el objeto exportado para detectar si es una exportación predeterminada o un exportsobjeto que se sobrescribió y luego lo usa en consecuencia.

    Esto funciona como se espera y te permite mantener tu código dentro src/vectors.tscomo antes. Para obtener más información sobre cómo esModuleInteropfunciona y qué cambios se realizan en el código JavaScript emitido, consulta la documentación de TypeScript para obtener información sobre estaesModuleInterop opción.

    Nota: Todos los cambios realizados en esta sección suponen que está utilizando un sistema de módulos que admite la sobrescritura del objeto exportado de un módulo. Actualmente, esos módulos son AMD y CommonJS. Si estuviera utilizando un sistema de módulos diferente, el compilador TypeScript le daría un error durante la compilación.

    Por ejemplo, si la compilerOptions.moduleconfiguración se estableciera para ES6apuntar al sistema de módulos ES, el compilador TypeScript nos daría múltiples errores, lo que se reduce a solo dos errores repetidos, 1202y 1203:

    "Output"src/vector2.ts:1:1 - error TS1203: Export assignment cannot be used when targeting ECMAScript modules. Consider using 'export default' or another module format instead.  1 export = class Vector2 {    ~~~~~~~~~~~~~~~~~~~~~~~~  2   constructor(public x: number, public y: number) {}    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~...  6   }    ~~~  7 };    ~~src/vectors.ts:1:1 - error TS1202: Import assignment cannot be used when targeting ECMAScript modules. Consider using 'import * as ns from "mod"', 'import {a} from "mod"', 'import d from "mod"', or another module format instead.1 import Vector2 = require("./vector2");

    Para obtener más información sobre cómo orientar el sistema de módulos ES, consulte la documentación del compilador TypeScript para la modulepropiedad .

    Conclusión

    TypeScript ofrece un sistema de módulos con todas las funciones y una sintaxis inspirada en la especificación de módulos ES, al tiempo que permite al desarrollador utilizar una variedad de otros sistemas de módulos en el código JavaScript emitido, como CommonJS , AMD , UMD , SystemJS y ES6 . Al utilizar las opciones importy exportdisponibles en TypeScript, puede asegurarse de que su código sea modular y compatible con el entorno más amplio de JavaScript. Saber cómo utilizar los módulos le permitirá organizar el código de su aplicación de forma concisa y eficiente, ya que los módulos son una parte fundamental para tener una base de código bien estructurada que sea fácil de ampliar y mantener.

    Para obtener más tutoriales sobre TypeScript, consulte nuestra página de la serie Cómo codificar en TypeScript .

    SUSCRÍBETE A NUESTRO BOLETÍN 
    No te pierdas de nuestro contenido ni de ninguna de nuestras guías para que puedas avanzar en los juegos que más te gustan.

    Deja una respuesta

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

    Subir

    Este sitio web utiliza cookies para mejorar tu experiencia mientras navegas por él. Este sitio web utiliza cookies para mejorar tu experiencia de usuario. Al continuar navegando, aceptas su uso. Mas informacion