Lección 98: Declaration Files (.d.ts)
🎯 Objetivo: Crear y entender archivos de declaración de tipos (.d.ts) para describir APIs de librerías JavaScript sin tipos nativos.
🧠 Concepto
1. ¿Qué son los archivos .d.ts?
Section titled “1. ¿Qué son los archivos .d.ts?”Los archivos .d.ts contienen declaraciones de tipos sin implementación. Son como “contratos” que describen la forma de una API.
💻 Ejemplo
declare function saludar(nombre: string): string;declare const VERSION: string;declare class Utilidad { static formatear(fecha: Date): string;}⚠️ Estos archivos NO contienen código ejecutable. Solo describen tipos para el compilador de TypeScript.
2. Declaraciones globales con declare
Section titled “2. Declaraciones globales con declare”declare function
Section titled “declare function”declare function calcularIVA(precio: number, tasa?: number): number;declare function $(selector: string): Element | null;declare class
Section titled “declare class”declare class Persona { constructor(nombre: string, edad: number); nombre: string; edad: number; saludar(): string; static crearAnonimo(): Persona;}declare namespace
Section titled “declare namespace”Para organizar declaraciones:
declare namespace MiLibreria { function init(config: Config): void; function logout(): void;
interface Config { apiKey: string; debug?: boolean; }
namespace Utilidades { function formatearFecha(fecha: Date): string; }}
// Uso:// MiLibreria.init({ apiKey: "abc" });// MiLibreria.Utilidades.formatearFecha(new Date());declare module
Section titled “declare module”Para librerías que se importan con ES modules:
declare module "mi-libreria" { export function init(config: Config): void; export function procesar(data: string): Resultado;
export interface Config { url: string; timeout?: number; }
export interface Resultado { exito: boolean; datos: unknown; }}3. Ambient declarations para librerías JS sin tipos
Section titled “3. Ambient declarations para librerías JS sin tipos”Cuando usas una librería JS que no tiene tipos, TypeScript se queja. Soluciones:
Opción 1: Declaración rápida para cualquier módulo
Section titled “Opción 1: Declaración rápida para cualquier módulo”declare module "libreria-sin-tipos";Esto permite importarla, pero todo será any. ⚠️ Temporal.
Opción 2: Declaración parcial
Section titled “Opción 2: Declaración parcial”declare module "libreria-sin-tipos" { export function hacerAlgo(input: string): number; export const version: string; // Lo demás será any implícitamente}Opción 3: @types/ desde npm
Section titled “Opción 3: @types/ desde npm”npm install --save-dev @types/lodashnpm install --save-dev @types/expressnpm install --save-dev @types/nodeTypeScript busca automáticamente en node_modules/@types/.
import _ from "lodash";_.chunk([1, 2, 3, 4], 2); // ✅ tipado4. Tripple-slash Directives
Section titled “4. Tripple-slash Directives”Son comentarios especiales que le dan instrucciones al compilador.
/// <reference types="node" />/// <reference path="./tipos-personalizados.d.ts" />/// <reference lib="es2021" />/// <reference types="...">
Section titled “/// <reference types="...">”Referencia a un paquete de @types/:
/// <reference types="express" />import express from "express";/// <reference path="...">
Section titled “/// <reference path="...">”Referencia a otro archivo de declaración local:
/// <reference path="./globals.d.ts" />/// <reference lib="...">
Section titled “/// <reference lib="...">”Incluye una librería interna de TypeScript:
/// <reference lib="es2021" />/// <reference lib="dom" />5. Escribir tipos para una librería propia
Section titled “5. Escribir tipos para una librería propia”Imagina que creaste una librería JS llamada simple-validator:
// node_modules/simple-validator/index.js (no TS)export function validateEmail(email) { /* ... */ }export function validatePhone(phone) { /* ... */ }export class ValidationError extends Error { /* ... */ }Paso 1: Crear el archivo index.d.ts
Section titled “Paso 1: Crear el archivo index.d.ts”declare module "simple-validator" { export function validateEmail(email: string): boolean; export function validatePhone(phone: string): boolean;
export class ValidationError extends Error { constructor(mensaje: string, campo: string); campo: string; }
export interface ValidationResult { valido: boolean; errores: string[]; }
export function validarTodo(datos: Record<string, string>): ValidationResult;}Paso 2: Agregar en package.json
Section titled “Paso 2: Agregar en package.json”{ "name": "simple-validator", "version": "1.0.0", "main": "index.js", "types": "index.d.ts"}Paso 3: O en tsconfig.json
Section titled “Paso 3: O en tsconfig.json”{ "compilerOptions": { "typeRoots": ["./node_modules/@types", "./types"] }}6. Sobrecarga de funciones en declaraciones
Section titled “6. Sobrecarga de funciones en declaraciones”declare function crearElemento(tag: "div"): HTMLDivElement;declare function crearElemento(tag: "span"): HTMLSpanElement;declare function crearElemento(tag: "a"): HTMLAnchorElement;declare function crearElemento(tag: string): HTMLElement;
// O más compacto:declare function crearElemento<T extends keyof HTMLElementTagNameMap>( tag: T): HTMLElementTagNameMap[T];7. Declaraciones con genéricos
Section titled “7. Declaraciones con genéricos”declare class Repositorio<T> { constructor(connectionString: string); obtenerPorId(id: string): Promise<T | null>; guardar(item: T): Promise<void>; eliminar(id: string): Promise<boolean>;}
declare function obtener<T>(url: string): Promise<T>;8. Aumentar tipos existentes (declaration merging)
Section titled “8. Aumentar tipos existentes (declaration merging)”// Ampliamos la interfaz Windowinterface Window { miPlugin?: { version: string; iniciar(): void; };}
// Ampliamos un móduloimport "express";
declare module "express" { interface Request { usuario?: { id: number; nombre: string; }; }}9. Archivo de declaración global típico
Section titled “9. Archivo de declaración global típico”// Variables globalesdeclare const API_BASE_URL: string;declare const ENV: "development" | "production" | "test";
// Funciones globalesdeclare function $(selector: string): { on: (evento: string, handler: Function) => void; html: (contenido?: string) => string | void;};
// Namespaces globalsdeclare namespace App { interface State { usuario: { nombre: string }; loading: boolean; } function getState(): State; function dispatch(action: { type: string; payload?: unknown }): void;}📝 Resumen: Los archivos .d.ts describen la API de librerías JS sin tipos nativos. Usa declare module, declare namespace y tripple-slash directives según el contexto. Para librerías populares, instala @types/ desde npm. Para tus propias librerías, crea el archivo .d.ts y referéncialo en package.json o tsconfig.json.