TypeScript
Tutorial TypeScript: Introducción a módulos
Aprende el sistema de módulos ES6 en TypeScript, su sintaxis, importaciones, exportaciones y resolución para código modular y escalable.
Aprende TypeScript y certifícateSistema de módulos ES6
El sistema de módulos ES6 (ECMAScript 2015) representa un avance significativo en la organización del código JavaScript, que TypeScript adopta y extiende con sus capacidades de tipado estático. Este sistema permite dividir el código en unidades independientes y reutilizables, facilitando el mantenimiento y la escalabilidad de las aplicaciones.
Antes de ES6, JavaScript carecía de un sistema de módulos nativo, lo que obligaba a los desarrolladores a utilizar patrones como el patrón módulo o bibliotecas externas como RequireJS o CommonJS. Con la llegada de ES6, se estandarizó finalmente una sintaxis oficial para trabajar con módulos.
Características principales del sistema de módulos ES6
Ámbito léxico: Cada módulo tiene su propio ámbito, lo que significa que las variables, funciones y clases declaradas en un módulo no están disponibles globalmente a menos que se exporten explícitamente.
Carga única: Los módulos se ejecutan una sola vez cuando se importan por primera vez, y las importaciones posteriores reutilizan la misma instancia del módulo.
Estructura estática: Las declaraciones de importación y exportación deben estar en el nivel superior del módulo, no pueden estar dentro de bloques condicionales o funciones.
Soporte para tipos: En TypeScript, los módulos pueden exportar no solo valores sino también definiciones de tipos, lo que mejora la documentación y la verificación del código.
Sintaxis básica en TypeScript
Un módulo ES6 en TypeScript es simplemente un archivo que contiene código TypeScript con al menos una declaración de exportación o importación. Veamos un ejemplo básico:
// math.ts
export function sum(a: number, b: number): number {
return a + b;
}
export function multiply(a: number, b: number): number {
return a * b;
}
// Constante que no se exporta (privada al módulo)
const PI = 3.14159;
// Función que utiliza la constante privada
export function calculateCircleArea(radius: number): number {
return PI * radius * radius;
}
En este ejemplo, las funciones sum
, multiply
y calculateCircleArea
están disponibles para ser importadas por otros módulos, mientras que la constante PI
permanece privada dentro del módulo.
Exportaciones por defecto
Además de las exportaciones con nombre, ES6 permite una exportación por defecto por módulo:
// user.ts
export default class User {
constructor(public name: string, public email: string) {}
greet(): string {
return `Hello, my name is ${this.name}`;
}
}
// También podemos tener exportaciones con nombre junto a la exportación por defecto
export function validateEmail(email: string): boolean {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
La exportación por defecto se utiliza cuando un módulo exporta principalmente un solo valor, función o clase.
Reexportación de módulos
El sistema de módulos ES6 permite reexportar elementos de otros módulos, lo que facilita la creación de módulos que agrupan funcionalidades relacionadas:
// index.ts - Módulo que agrupa y reexporta
export { sum, multiply } from './math';
export { default as User, validateEmail } from './user';
// También podemos renombrar al reexportar
export { sum as addition } from './math';
Esta técnica es útil para crear APIs públicas bien organizadas, ocultando la estructura interna de los módulos.
Importaciones dinámicas
ES6 también introdujo la capacidad de importar módulos dinámicamente usando la función import()
, que devuelve una promesa:
// En TypeScript podemos tipar el resultado de la importación dinámica
async function loadMathModule() {
try {
const math = await import('./math');
console.log(math.sum(5, 3)); // 8
} catch (error) {
console.error('Error loading module:', error);
}
}
// O usar la sintaxis then/catch
function loadUserModule() {
import('./user')
.then(module => {
const admin = new module.default('Admin', 'admin@example.com');
console.log(admin.greet());
})
.catch(error => {
console.error('Error loading module:', error);
});
}
Las importaciones dinámicas son especialmente útiles para:
- Carga bajo demanda de módulos
- Implementación de code splitting
- Carga condicional basada en la lógica de la aplicación
Interoperabilidad con otros sistemas de módulos
TypeScript permite trabajar con diferentes sistemas de módulos mediante la configuración del compilador. En el archivo tsconfig.json
, podemos especificar el sistema de módulos de destino:
{
"compilerOptions": {
"module": "es2015", // También: "commonjs", "amd", "system", "umd", "esnext"
// Otras opciones...
}
}
Esta flexibilidad permite que el código TypeScript se integre con diferentes entornos y sistemas de módulos.
Ventajas del sistema de módulos ES6 en TypeScript
Encapsulación: Cada módulo tiene su propio ámbito, lo que evita la contaminación del espacio de nombres global.
Organización del código: Facilita la división del código en unidades lógicas y manejables.
Tipado explícito: TypeScript añade la capacidad de exportar e importar tipos, interfaces y otras construcciones de tipado.
Compatibilidad con herramientas modernas: El sistema de módulos ES6 es compatible con empaquetadores como Webpack, Rollup y Parcel.
Carga asíncrona: Soporte nativo para importaciones dinámicas que permiten cargar código bajo demanda.
El sistema de módulos ES6 en TypeScript proporciona una base sólida para construir aplicaciones modulares y bien estructuradas, aprovechando tanto las ventajas de la modularidad de ES6 como las capacidades de tipado estático de TypeScript.
Import y export
Las declaraciones import y export son la base del sistema de módulos ES6 en TypeScript, permitiendo compartir código entre diferentes archivos de manera estructurada y segura. Estas declaraciones definen qué elementos están disponibles fuera del módulo y cómo pueden ser utilizados por otros módulos.
Exportación de elementos
TypeScript ofrece varias formas de exportar elementos desde un módulo:
Exportaciones con nombre
La forma más común de exportar elementos es mediante exportaciones con nombre, que permiten exponer múltiples valores desde un mismo módulo:
// logger.ts
export const LOG_LEVEL = {
INFO: 'info',
WARNING: 'warning',
ERROR: 'error'
};
export interface LogMessage {
level: string;
message: string;
timestamp: Date;
}
export class Logger {
log(level: string, message: string): void {
console.log(`[${level.toUpperCase()}]: ${message}`);
}
}
export function formatLogMessage(msg: LogMessage): string {
return `[${msg.level}][${msg.timestamp.toISOString()}] ${msg.message}`;
}
En este ejemplo, exportamos una constante, una interfaz, una clase y una función, todos con nombres específicos que se utilizarán al importarlos.
Exportación por defecto
Cuando un módulo tiene un elemento principal, podemos utilizar la exportación por defecto:
// config.ts
interface Config {
apiUrl: string;
timeout: number;
retries: number;
}
// Exportación por defecto (solo puede haber una por módulo)
export default {
apiUrl: 'https://api.example.com',
timeout: 5000,
retries: 3
} as Config;
También podemos exportar por defecto clases, funciones o cualquier otro valor:
// api-client.ts
export default class ApiClient {
constructor(private baseUrl: string) {}
async get<T>(endpoint: string): Promise<T> {
const response = await fetch(`${this.baseUrl}/${endpoint}`);
return response.json();
}
}
Exportaciones combinadas
Un módulo puede combinar exportaciones con nombre y una exportación por defecto:
// validation.ts
// Exportación con nombre
export function isEmail(value: string): boolean {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(value);
}
// Exportación por defecto
export default class Validator {
validate(schema: Record<string, (value: any) => boolean>, data: any): boolean {
for (const [field, validator] of Object.entries(schema)) {
if (!validator(data[field])) {
return false;
}
}
return true;
}
}
Exportación de tipos
Una característica poderosa de TypeScript es la capacidad de exportar tipos, interfaces, enums y otras construcciones de tipado:
// types.ts
export type UserId = string;
export interface User {
id: UserId;
name: string;
email: string;
role: UserRole;
}
export enum UserRole {
ADMIN = 'admin',
EDITOR = 'editor',
VIEWER = 'viewer'
}
export interface ApiResponse<T> {
data: T;
status: number;
message: string;
}
Importación de elementos
TypeScript ofrece varias formas de importar elementos desde otros módulos:
Importación de elementos con nombre
Para importar elementos exportados con nombre:
// app.ts
import { LOG_LEVEL, Logger, LogMessage, formatLogMessage } from './logger';
const logger = new Logger();
logger.log(LOG_LEVEL.INFO, 'Aplicación iniciada');
const message: LogMessage = {
level: LOG_LEVEL.WARNING,
message: 'Recurso no encontrado',
timestamp: new Date()
};
console.log(formatLogMessage(message));
Importación de exportaciones por defecto
Para importar un elemento exportado por defecto:
// app.ts
import config from './config';
import ApiClient from './api-client';
const client = new ApiClient(config.apiUrl);
client.get('users').then(data => console.log(data));
Importaciones combinadas
Podemos combinar importaciones por defecto y con nombre en una sola declaración:
// app.ts
import Validator, { isEmail } from './validation';
const validator = new Validator();
console.log(isEmail('user@example.com')); // true
const userSchema = {
email: isEmail,
name: (value: string) => value.length > 0
};
validator.validate(userSchema, {
email: 'user@example.com',
name: 'John'
}); // true
Importación de todo el módulo
Podemos importar todo el contenido de un módulo como un objeto:
// app.ts
import * as loggerModule from './logger';
const logger = new loggerModule.Logger();
logger.log(loggerModule.LOG_LEVEL.INFO, 'Aplicación iniciada');
Renombrar importaciones
Podemos renombrar elementos al importarlos para evitar conflictos de nombres:
// app.ts
import { Logger as LogService, LOG_LEVEL as LogLevels } from './logger';
import { User as UserModel } from './types';
const logger = new LogService();
logger.log(LogLevels.INFO, 'Procesando usuario');
const user: UserModel = {
id: '123',
name: 'Alice',
email: 'alice@example.com',
role: 'admin'
};
Importación de tipos
TypeScript permite importar tipos, interfaces y otras construcciones de tipado:
// user-service.ts
import { User, UserId, UserRole, ApiResponse } from './types';
export async function getUser(id: UserId): Promise<ApiResponse<User>> {
// Implementación...
return {
data: {
id,
name: 'John Doe',
email: 'john@example.com',
role: UserRole.VIEWER
},
status: 200,
message: 'Success'
};
}
Importación de archivos no TypeScript
TypeScript también permite importar recursos que no son código TypeScript, como archivos JSON, CSS o imágenes, si se configura adecuadamente:
// Para importar JSON (requiere "resolveJsonModule": true en tsconfig.json)
import settings from './settings.json';
console.log(settings.theme);
// Para importar otros recursos (requiere definiciones de tipos adecuadas)
import './styles.css';
import logoUrl from './logo.png';
Importaciones de solo tipo
TypeScript 3.8 introdujo la sintaxis de importación de solo tipo, útil para evitar que las importaciones de tipos afecten al código JavaScript generado:
// Solo importa el tipo, no el valor
import type { User, ApiResponse } from './types';
function processUser(user: User): ApiResponse<User> {
// Implementación...
return {
data: user,
status: 200,
message: 'Processed'
};
}
Reexportación de módulos
Podemos reexportar elementos de otros módulos para crear APIs más limpias:
// index.ts
// Reexportar elementos individuales
export { Logger, LOG_LEVEL } from './logger';
export { default as config } from './config';
// Reexportar y renombrar
export { isEmail as validateEmail } from './validation';
// Reexportar todo
export * from './types';
// Reexportar todo excepto algunos elementos
export * from './utils';
export { default as Utils } from './utils';
Las declaraciones import y export en TypeScript proporcionan una forma flexible y potente de organizar el código, facilitando la creación de aplicaciones modulares y mantenibles con un sistema de tipos robusto.
Módulos vs scripts
En TypeScript, la distinción entre módulos y scripts representa dos enfoques fundamentalmente diferentes para organizar y ejecutar código. Entender esta diferencia es crucial para estructurar correctamente las aplicaciones y evitar problemas comunes de ámbito y accesibilidad.
Ámbito global vs ámbito de módulo
La diferencia más significativa entre scripts y módulos radica en cómo manejan el ámbito de las declaraciones:
Scripts: Operan en el ámbito global. Todas las variables, funciones y clases declaradas en un script están disponibles globalmente y pueden ser accedidas por cualquier otro script que se cargue en la misma página o contexto.
Módulos: Utilizan un ámbito local. Las declaraciones dentro de un módulo están encapsuladas y solo son accesibles dentro del propio módulo, a menos que se exporten explícitamente.
Veamos un ejemplo que ilustra esta diferencia:
// Como script (archivo.ts sin import/export)
function saludar(nombre: string): void {
console.log(`Hola, ${nombre}!`);
}
const usuario = "Ana";
saludar(usuario); // Funciona correctamente
// Como módulo (modulo.ts con al menos un import/export)
export function saludar(nombre: string): void {
console.log(`Hola, ${nombre}!`);
}
const usuario = "Ana"; // Esta constante es privada al módulo
saludar(usuario); // Funciona correctamente
En el primer caso, saludar
y usuario
están en el ámbito global. En el segundo, solo saludar
está disponible fuera del módulo, mientras que usuario
permanece privado.
Identificación de módulos vs scripts
TypeScript utiliza una regla simple para determinar si un archivo es un módulo o un script:
- Si un archivo contiene al menos una declaración
import
oexport
en el nivel superior, se trata como un módulo. - Si un archivo no contiene ninguna declaración
import
oexport
, se trata como un script.
Esta distinción es automática y tiene importantes implicaciones para el comportamiento del código.
Declaraciones en el ámbito global
En un script, las declaraciones pueden colisionar con otras declaraciones globales:
// script1.ts
const MAX_USERS = 100;
function initialize() { /* ... */ }
// script2.ts
const MAX_USERS = 200; // Error: Identificador duplicado 'MAX_USERS'
function initialize() { /* ... */ } // Error: Identificador duplicado 'initialize'
En cambio, en los módulos no hay riesgo de colisión:
// modulo1.ts
export const MAX_USERS = 100;
export function initialize() { /* ... */ }
// modulo2.ts
export const MAX_USERS = 200; // No hay error, son módulos diferentes
export function initialize() { /* ... */ } // No hay error, son módulos diferentes
Acceso a variables globales
Los scripts pueden acceder y modificar variables globales directamente:
// script.ts
// Accede a una variable global del navegador
window.onload = () => {
console.log("Página cargada");
};
// Modifica el objeto global
globalThis.miVariable = "valor global";
Los módulos también pueden acceder a variables globales, pero es más explícito:
// modulo.ts
export function inicializarUI() {
// Accede a una variable global del navegador
window.onload = () => {
console.log("Página cargada desde módulo");
};
// Modifica el objeto global (menos común en módulos)
globalThis.configuracion = { tema: "oscuro" };
}
Declaraciones de tipos
El manejo de las declaraciones de tipos también difiere entre scripts y módulos:
// Como script
interface Usuario {
nombre: string;
edad: number;
}
// Esta interfaz está disponible globalmente
const usuario: Usuario = { nombre: "Carlos", edad: 30 };
// Como módulo
export interface Usuario {
nombre: string;
edad: number;
}
// La interfaz solo está disponible si se importa
const usuario: Usuario = { nombre: "Carlos", edad: 30 };
Archivos de declaración (.d.ts)
Los archivos de declaración se comportan de manera especial:
- Un archivo
.d.ts
sin declaracionesimport/export
añade tipos al ámbito global. - Un archivo
.d.ts
con declaracionesimport/export
define un módulo de declaración.
// global.d.ts (ámbito global)
interface Window {
analytics: {
trackEvent(name: string, properties?: object): void;
}
}
// api.d.ts (módulo de declaración)
export interface ApiResponse<T> {
data: T;
status: number;
message: string;
}
Conversión entre scripts y módulos
Convertir un script en un módulo es tan simple como añadir una exportación:
// Antes: script.ts
function utilidad() {
return "Función útil";
}
// Después: módulo.ts
export function utilidad() {
return "Función útil";
}
Para mantener la compatibilidad con código existente al convertir scripts en módulos, se puede usar la exportación de ámbito global:
// modulo.ts
export {}; // Convierte el archivo en un módulo
// Declara en el ámbito global
declare global {
interface Window {
misFunciones: {
calcular(): number;
}
}
}
// Implementa la funcionalidad
window.misFunciones = {
calcular: () => 42
};
Consideraciones prácticas
Al decidir entre módulos y scripts, considera:
Mantenibilidad: Los módulos facilitan la organización del código en unidades independientes y reutilizables.
Encapsulación: Los módulos permiten ocultar detalles de implementación y exponer solo una API pública.
Compatibilidad: Los scripts pueden ser necesarios para ciertos entornos o casos de uso específicos, como scripts de usuario o extensiones de navegador.
Herramientas de construcción: Los módulos funcionan mejor con empaquetadores modernos como Webpack, Rollup o esbuild.
// Ejemplo de módulo bien estructurado
// api-client.ts
export interface RequestOptions {
headers?: Record<string, string>;
timeout?: number;
}
export class ApiClient {
private baseUrl: string;
constructor(baseUrl: string) {
this.baseUrl = baseUrl;
}
async get<T>(endpoint: string, options?: RequestOptions): Promise<T> {
const url = `${this.baseUrl}/${endpoint}`;
const response = await fetch(url, {
headers: options?.headers,
signal: options?.timeout ? AbortSignal.timeout(options.timeout) : undefined
});
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
return response.json();
}
}
Migración de scripts a módulos
Al migrar una base de código de scripts a módulos, sigue estos pasos:
Identifica dependencias: Determina qué scripts dependen de otros.
Comienza por los más básicos: Convierte primero los scripts con menos dependencias.
Exporta interfaces públicas: Decide qué funcionalidades deben exportarse.
Actualiza referencias: Modifica el código que utiliza los scripts convertidos para que importe los módulos.
Prueba incrementalmente: Verifica que cada conversión funcione antes de continuar.
// Antes (script)
function formatDate(date) {
return new Intl.DateTimeFormat('es').format(date);
}
// Después (módulo)
export function formatDate(date: Date): string {
return new Intl.DateTimeFormat('es').format(date);
}
En resumen, mientras que los scripts son adecuados para pequeños fragmentos de código o scripts de utilidad, los módulos ofrecen una estructura más robusta para aplicaciones complejas, facilitando la organización, el mantenimiento y la escalabilidad del código TypeScript.
Resolución de módulos
La resolución de módulos es el proceso mediante el cual TypeScript localiza y carga los archivos correspondientes a las declaraciones de importación en el código. Este mecanismo es fundamental para el correcto funcionamiento del sistema de módulos, ya que determina cómo el compilador encuentra los módulos referenciados en las sentencias import
.
TypeScript implementa diferentes estrategias de resolución de módulos para adaptarse a diversos entornos y configuraciones de proyecto. Entender estas estrategias es esencial para evitar errores comunes y estructurar correctamente las aplicaciones.
Estrategias de resolución de módulos
TypeScript soporta principalmente dos estrategias de resolución:
- Clásica: Basada en la resolución de Node.js, utilizada para módulos con rutas relativas.
- Node: Emula el mecanismo de resolución de Node.js para módulos tanto relativos como no relativos.
La estrategia utilizada se configura mediante la opción moduleResolution
en el archivo tsconfig.json
:
{
"compilerOptions": {
"moduleResolution": "node", // Opciones: "node", "classic", "bundler", "node16" o "nodenext"
// Otras opciones...
}
}
Resolución de rutas relativas
Cuando importamos un módulo utilizando una ruta relativa (que comienza con ./
o ../
), TypeScript busca el archivo siguiendo estas reglas:
// Importación con ruta relativa
import { Usuario } from './modelos/usuario';
El proceso de resolución para rutas relativas sigue este orden:
- Busca el archivo exacto:
./modelos/usuario.ts
- Busca el archivo con extensiones:
./modelos/usuario.js
,./modelos/usuario.jsx
,./modelos/usuario.d.ts
- Busca un archivo index en el directorio:
./modelos/usuario/index.ts
,./modelos/usuario/index.js
, etc.
Por ejemplo, si tenemos esta estructura de archivos:
src/
├── app.ts
└── modelos/
├── usuario.ts
└── producto/
└── index.ts
Estas importaciones se resolverán así:
// En app.ts
import { Usuario } from './modelos/usuario'; // Resuelve a ./modelos/usuario.ts
import { Producto } from './modelos/producto'; // Resuelve a ./modelos/producto/index.ts
Resolución de módulos no relativos
Para importaciones no relativas (sin ./
o ../
), TypeScript utiliza un algoritmo más complejo que depende de la estrategia de resolución configurada:
// Importación no relativa
import { useState } from 'react';
Con la estrategia node
, el proceso sigue estas reglas:
- Busca en la carpeta
node_modules
del directorio actual - Si no lo encuentra, sube un nivel y busca en
node_modules
allí - Continúa subiendo hasta encontrar el módulo o llegar a la raíz del sistema de archivos
Dentro de cada carpeta node_modules
, busca:
- Un archivo con el nombre exacto o con extensiones compatibles
- El campo
"main"
en elpackage.json
del paquete - Un archivo
index.js
oindex.ts
en la carpeta del paquete
Mapeo de rutas con path aliases
TypeScript permite definir alias de rutas para simplificar las importaciones y evitar rutas relativas complejas:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@modelos/*": ["src/modelos/*"],
"@utils/*": ["src/utils/*"],
"@components": ["src/components/index"]
}
}
}
Con esta configuración, podemos importar así:
// Sin alias
import { Usuario } from '../../modelos/usuario';
// Con alias
import { Usuario } from '@modelos/usuario';
import { formatearFecha } from '@utils/fecha';
import { Button, Card } from '@components';
Los alias de rutas son especialmente útiles en proyectos grandes con estructuras de directorios profundas, ya que:
- Simplifican las importaciones
- Evitan rutas relativas complejas (
../../../../
) - Facilitan la refactorización de la estructura de archivos
Resolución de tipos de declaración
TypeScript también busca archivos de declaración (.d.ts
) para proporcionar información de tipos para módulos JavaScript:
- Busca archivos
.d.ts
junto a los archivos JavaScript - Busca en el directorio
@types
dentro denode_modules
para definiciones de tipos de terceros
Por ejemplo, para usar una biblioteca como lodash
:
import _ from 'lodash'; // TypeScript busca tipos en @types/lodash
Para que esto funcione, necesitamos instalar los tipos:
npm install --save-dev @types/lodash
Extensiones de archivo en importaciones
En TypeScript, normalmente omitimos las extensiones de archivo en las importaciones:
// Recomendado
import { Usuario } from './modelos/usuario';
// No es necesario (y puede causar problemas)
import { Usuario } from './modelos/usuario.ts';
Sin embargo, con la introducción de ESM en Node.js, las extensiones se vuelven obligatorias. Para proyectos que apuntan a este entorno, TypeScript ofrece las estrategias node16
o nodenext
:
{
"compilerOptions": {
"module": "node16",
"moduleResolution": "node16"
}
}
Con esta configuración, las importaciones deben incluir la extensión que tendrá el archivo después de la compilación:
// Para módulos ESM en Node.js
import { Usuario } from './modelos/usuario.js'; // Nota la extensión .js, no .ts
Resolución de módulos en monorepos
En proyectos monorepo (múltiples paquetes en un solo repositorio), la resolución de módulos puede complicarse. TypeScript ofrece opciones para facilitar las referencias entre paquetes:
{
"compilerOptions": {
"composite": true,
"declaration": true,
"declarationMap": true,
"rootDir": "src",
"outDir": "dist"
},
"references": [
{ "path": "../paquete-comun" }
]
}
Esta configuración permite:
- Referencias de proyecto: Importar directamente desde otros paquetes del monorepo
- Compilación incremental: Solo recompilar lo que ha cambiado
Personalización de la resolución con plugins
Para casos más complejos, TypeScript permite plugins de resolución que pueden modificar el proceso:
{
"compilerOptions": {
"plugins": [
{ "name": "typescript-plugin-css-modules" }
]
}
}
Estos plugins pueden añadir soporte para:
- Importación de archivos no JavaScript (CSS, SVG, etc.)
- Resolución dinámica basada en reglas personalizadas
- Integración con sistemas de módulos personalizados
Depuración de problemas de resolución
Cuando enfrentamos problemas de resolución de módulos, podemos usar la opción --traceResolution
para ver el proceso completo:
tsc --traceResolution
Esta opción muestra información detallada sobre:
- Archivos buscados durante la resolución
- Estrategias aplicadas para cada importación
- Razones de fallo cuando no se encuentra un módulo
Optimización de la resolución de módulos
Para mejorar el rendimiento de la resolución, podemos:
- Usar la opción
"moduleDetection": "force"
para tratar todos los archivos como módulos - Configurar
"skipLibCheck": true
para omitir la verificación de archivos de declaración de bibliotecas - Utilizar
"typeRoots"
para limitar dónde buscar definiciones de tipos
{
"compilerOptions": {
"moduleDetection": "force",
"skipLibCheck": true,
"typeRoots": ["./node_modules/@types", "./tipos"]
}
}
Resolución en diferentes entornos
La configuración óptima varía según el entorno de destino:
- Navegador con bundlers (Webpack, Rollup):
{
"moduleResolution": "node",
"module": "esnext"
}
- Node.js moderno (con ESM):
{
"moduleResolution": "nodenext",
"module": "nodenext"
}
- Deno:
{
"moduleResolution": "node",
"module": "esnext",
"lib": ["deno.ns", "deno.unstable"]
}
La correcta configuración de la resolución de módulos es crucial para el desarrollo eficiente con TypeScript, ya que afecta directamente a la experiencia de desarrollo, el rendimiento de la compilación y la portabilidad del código entre diferentes entornos.
Ejercicios de esta lección Introducción a módulos
Evalúa tus conocimientos de esta lección Introducción a módulos con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.
Funciones
Reto composición de funciones
Reto tipos especiales
Reto tipos genéricos
Módulos
Polimorfismo
Funciones TypeScript
Interfaces
Funciones puras
Reto namespaces
Funciones flecha
Polimorfismo
Operadores
Conversor de unidades
Funciones flecha
Control de flujo
Herencia
Clases
Proyecto validación de tipado
Clases y objetos
Encapsulación
Herencia
Proyecto sistema de votación
Reto genéricos con clases
Inmutabilidad
Interfaces
Funciones de alto orden
Reto map y filter
Control de flujo
Interfaces
Reto funciones orden superior
Herencia y clases abstractas
Reto tipos mapped
Herencia de clases
Reto funciones puras
Variables y constantes
Introducción a TypeScript
Reto testing unitario
Funciones de primera clase
Clases
OOP y CRUD en TypeScript
Interfaces y su implementación
Tipos genéricos
Namespaces
Proyecto calculadora gastos
Operadores y expresiones
Proyecto generador de contraseñas
Reto unión e intersección
Encapsulación
Tipos de unión e intersección
Tipos de unión e intersección
Reto hola mundo en TS
Variables y constantes
Funciones puras
Control de flujo
Introducción a TypeScript
Resolución de módulos
Control de flujo
Reto tipos de utilidad
Reto tipos literales y condicionales
Reto exportar e importar
Propiedades y métodos
Tipos de utilidad
Clases y objetos
Tipos de datos, variables y constantes
Proyecto Minigestor de tareas
Operadores
Funciones flecha y contexto
Funciones
Reto type aliases
Funciones de alto orden
Funciones y parámetros tipados
Tipos literales
Reto enums
Tipos de utilidad
Modificadores de acceso y encapsulación
Polimorfismo
Tipos genéricos
Reto módulos
Tipos literales
Inmutabilidad
Proyecto Generator de datos
Variables y constantes
Funciones de primera clase
Todas las lecciones de TypeScript
Accede a todas las lecciones de TypeScript y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Introducción A Typescript
Introducción Y Entorno
Instalación Y Configuración De Typescript
Introducción Y Entorno
Tipos De Datos, Variables Y Constantes
Sintaxis
Operadores Y Expresiones
Sintaxis
Control De Flujo
Sintaxis
Funciones Y Parámetros Tipados
Sintaxis
Funciones Flecha Y Contexto
Sintaxis
Enums
Sintaxis
Type Aliases Y Aserciones De Tipo
Sintaxis
Clases Y Objetos
Programación Orientada A Objetos
Interfaces Y Su Implementación
Programación Orientada A Objetos
Modificadores De Acceso Y Encapsulación
Programación Orientada A Objetos
Herencia Y Clases Abstractas
Programación Orientada A Objetos
Polimorfismo
Programación Orientada A Objetos
Decoradores Básicos
Programación Orientada A Objetos
Propiedades Y Métodos
Programación Orientada A Objetos
Inmutabilidad
Programación Funcional
Funciones Puras
Programación Funcional
Funciones De Primera Clase
Programación Funcional
Funciones De Alto Orden
Programación Funcional
Conceptos Básicos E Inmutabilidad
Programación Funcional
Funciones De Primera Clase Y Orden Superior
Programación Funcional
Composición De Funciones
Programación Funcional
Métodos Funcionales De Arrays (Map, Filter, Reduce)
Programación Funcional
Tipos Literales
Tipos Intermedios Y Avanzados
Tipos Genéricos
Tipos Intermedios Y Avanzados
Tipos De Unión E Intersección
Tipos Intermedios Y Avanzados
Tipos De Utilidad
Tipos Intermedios Y Avanzados
Unknown, Never Y Tipos Especiales
Tipos Intermedios Y Avanzados
Tipos Mapped
Tipos Intermedios Y Avanzados
Genéricos Con Clases E Interfaces
Tipos Intermedios Y Avanzados
Módulos
Namespaces Y Módulos
Namespaces
Namespaces Y Módulos
Resolución De Módulos
Namespaces Y Módulos
Exportación E Importación De Módulos
Namespaces Y Módulos
Introducción A Módulos
Namespaces Y Módulos
Testing Unitario En Typescript
Testing
En esta lección
Objetivos de aprendizaje de esta lección
- Comprender el sistema de módulos ES6 y su integración en TypeScript.
- Aprender a usar las declaraciones import y export, incluyendo exportaciones por defecto y reexportaciones.
- Diferenciar entre módulos y scripts en TypeScript y sus implicaciones en el ámbito y organización del código.
- Entender el proceso de resolución de módulos y cómo configurar rutas, alias y estrategias en tsconfig.json.
- Conocer buenas prácticas para organizar y migrar código hacia módulos en proyectos TypeScript.