TypeScript de Cero a Experto / TS en el mundo real
Declaration files: tipar lo que TS no ve
No todo el código que usas tiene tipos: librerías viejas en JavaScript puro, variables
globales inyectadas por un script, propiedades que agregas a window. Los declaration
files (.d.ts) son la forma de darle a TypeScript conocimiento sobre código que no
puede ver —tipos sin implementación, puros contratos. Es la herramienta para que TS
entienda el mundo real que lo rodea.
El manual de instrucciones sin la máquina
declare: describir sin implementar
Un archivo .d.ts contiene solo TIPOS —descripciones—, nunca código ejecutable. La
palabra declare dice "esto existe en algún lado, créeme y tipéalo":
// un archivo .d.ts: solo declaraciones, cero implementación
// una variable global que un <script> externo puso en window:
declare const VERSION_APP: string;
// una función global disponible en el entorno:
declare function rastrear(evento: string): void;
// ahora puedes usarlas en tu código TS con tipos, sin que TS vea su código:
console.log(VERSION_APP.toUpperCase()); // ✓ TS sabe que es string
rastrear("pagina_vista"); // ✓ tipadaEn un .d.ts no hay cuerpos de función ni valores —solo formas. declare const VERSION_APP: string le promete a TS "existe una variable global llamada así, de tipo
string" (puesta quizá por un <script> en el HTML). TS te deja usarla tipada, aunque su
valor real llegue de fuera. Es el manual para lo que existe en runtime pero TS no ve en
tu código.
Tipar una librería sin tipos
Si usas una librería JavaScript que no trae tipos (ni un paquete @types/), la tipas
con declare module:
// una librería vieja 'calculadora-legacy' sin tipos propios:
declare module "calculadora-legacy" {
export function sumar(a: number, b: number): number;
export function formatear(valor: number): string;
export const version: string;
}
// ahora en tu código, el import está tipado:
// import { sumar, formatear } from "calculadora-legacy";
// sumar(2, 3); ✓ tipado
// sumar("2", 3); ❌ error, como debe serAmpliar tipos existentes: module augmentation
A veces no quieres crear un tipo nuevo, sino AMPLIAR uno que ya existe —agregar una
propiedad a window, o a los tipos de una librería. Aquí vuelve el declaration merging
de las interfaces (módulo 3):
// agregar una propiedad global a Window (que tu app pone en runtime):
declare global {
interface Window {
miApp: {
version: string;
usuario: { id: number } | null;
};
}
}
// ahora window.miApp está tipado en TODO el proyecto:
// window.miApp.version.toUpperCase(); ✓
// window.miApp.usuario?.id; ✓
export {}; // esto convierte el archivo en un módulo (necesario para 'declare global')declare global { interface Window { ... } } FUSIONA tu declaración con la interface
Window nativa (declaration merging, módulo 3), agregándole miApp. Es el patrón
estándar para tipar lo que tu app inyecta en el objeto global. El export {} del final
es un truco necesario: convierte el archivo en un módulo, requisito de declare global.
Lo mismo sirve para ampliar los tipos de Express, de Vue, o de cualquier librería con
puntos de extensión.
Un <script> externo en tu HTML define una variable global window.CONFIG con datos. En tu código TS, usar window.CONFIG da error 'Property CONFIG does not exist on Window'. ¿Cómo lo tipas?
Mini-reto
Tipa el entorno (en un proyecto TS con un env.d.ts): 1) declara una variable global
declare const API_URL: string (que imaginas puesta por tu bundler); 2) amplía Window
con declare global para agregar una propiedad analytics: { rastrear(evento: string): void }; 3) usa ambas en un .ts y confirma que TS las reconoce tipadas. Escribiste un
manual para código que TS no ve.
Qué sigue
Última lección del módulo: las clases a fondo en TypeScript —modificadores de acceso, propiedades de parámetro, clases abstractas— y una probada de los DECORADORES, la sintaxis para añadir comportamiento a clases y métodos que verás en Angular y NestJS. El TypeScript orientado a objetos que usan los frameworks del backend.