Skip to content

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

Los archivos .d.ts contienen declaraciones de tipos sin implementación. Son como “contratos” que describen la forma de una API.

💻 Ejemplo

mi-libreria.d.ts
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.


declare function calcularIVA(precio: number, tasa?: number): number;
declare function $(selector: string): Element | null;
declare class Persona {
constructor(nombre: string, edad: number);
nombre: string;
edad: number;
saludar(): string;
static crearAnonimo(): Persona;
}

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());

Para librerías que se importan con ES modules:

types/mi-libreria.d.ts
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”
src/ambient.d.ts
declare module "libreria-sin-tipos";

Esto permite importarla, pero todo será any. ⚠️ Temporal.

declare module "libreria-sin-tipos" {
export function hacerAlgo(input: string): number;
export const version: string;
// Lo demás será any implícitamente
}
Terminal window
npm install --save-dev @types/lodash
npm install --save-dev @types/express
npm install --save-dev @types/node

TypeScript busca automáticamente en node_modules/@types/.

import _ from "lodash";
_.chunk([1, 2, 3, 4], 2); // ✅ tipado

Son comentarios especiales que le dan instrucciones al compilador.

/// <reference types="node" />
/// <reference path="./tipos-personalizados.d.ts" />
/// <reference lib="es2021" />

Referencia a un paquete de @types/:

/// <reference types="express" />
import express from "express";

Referencia a otro archivo de declaración local:

/// <reference path="./globals.d.ts" />

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 { /* ... */ }
node_modules/simple-validator/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;
}
{
"name": "simple-validator",
"version": "1.0.0",
"main": "index.js",
"types": "index.d.ts"
}
{
"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];

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 Window
interface Window {
miPlugin?: {
version: string;
iniciar(): void;
};
}
// Ampliamos un módulo
import "express";
declare module "express" {
interface Request {
usuario?: {
id: number;
nombre: string;
};
}
}

global.d.ts
// Variables globales
declare const API_BASE_URL: string;
declare const ENV: "development" | "production" | "test";
// Funciones globales
declare function $(selector: string): {
on: (evento: string, handler: Function) => void;
html: (contenido?: string) => string | void;
};
// Namespaces globals
declare 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.