---
name: build-errors-typescript
description: >
  Resolución de errores de compilación TypeScript: tsc, tsconfig.json, errores de
  tipos, generics, declaration files y bundlers (Vite, esbuild, webpack). Cargar
  cuando un build TypeScript falle, tsc reporte errores de tipos, o haya problemas
  con la configuración del compilador o del bundler.
version: "1.0.0"
herramientasPermitidas: [Read, Bash, Grep]
exclusiones:
  - "No cargar para errores de lógica o comportamiento en runtime JavaScript — si el código compila pero falla en ejecución (undefined is not a function, Promise sin await), no es un error de compilación TypeScript."
  - "No cargar para errores específicos de frameworks sobre TypeScript (Angular TS2xxx en templates, NestJS decorators) — esos tienen contexto adicional de framework; cargar `angular-moderno`, `nestjs-experto` o `build-errors-nextjs`."
  - "No cargar para decidir la configuración óptima de tsconfig desde cero en un proyecto nuevo — eso es diseño de stack; cargar `typescript-avanzado` para configuración y patrones generales."
  - "No cargar cuando el error es de ESLint o Prettier (no de tsc) — los errores de style/lint no son errores de compilación TypeScript."
evolvable: true  # default para skill estandar
---
# Build Errors TypeScript — Diagnóstico y Solución

## Cuándo NO cargar

- El error ocurre en runtime JavaScript (no en `tsc`) — si el build pasa pero el navegador/Node lanza errores, no es un problema de TypeScript.
- El error viene de un framework encima de TypeScript (Angular, NestJS) — cargar el skill específico del framework porque el error puede tener semántica adicional.
- La pregunta es cómo configurar tsconfig para un proyecto nuevo — para diseño de configuración cargar `typescript-avanzado`.

## Cuándo cargar

- `tsc` falla con errores de tipos, generics o declaration files
- `npm run build` o `yarn build` falla en la etapa de type-checking
- Errores de `tsconfig.json` (paths, module resolution, strict mode)
- Problemas con `@types/*` (conflictos, tipos faltantes, versiones incompatibles)
- Errores de bundlers (Vite, esbuild, webpack) relacionados con TypeScript
- Errores de ESM vs CommonJS en proyectos TypeScript

---

## Errores de tsc — tipos y asignación

### `TS2322: Type 'X' is not assignable to type 'Y'`

**Causa**: asignación de un valor cuyo tipo no coincide con el esperado.

```typescript
// MAL
const edad: number = "25";  // string no es number

// BIEN — verificar el tipo real del valor
const edad: number = parseInt("25", 10);

// Caso frecuente: respuestas de API
interface Usuario { id: number; nombre: string }
// La API puede devolver id como string — validar en runtime
const usuario: Usuario = await api.get("/users/1"); // puede fallar si id viene como "1"
```

**Gotcha con unions y narrowing**:
```typescript
// MAL — TS no sabe cuál es el tipo dentro de la union
function procesar(valor: string | number) {
  return valor.toFixed(2);  // TS2339: toFixed no existe en string
}

// BIEN — narrowing con typeof
function procesar(valor: string | number) {
  if (typeof valor === "number") {
    return valor.toFixed(2);
  }
  return parseFloat(valor).toFixed(2);
}
```

### `TS2345: Argument of type 'X' is not assignable to parameter of type 'Y'`

**Causa frecuente**: pasar `null` o `undefined` donde se espera un tipo definido.

```typescript
// MAL — strictNullChecks detecta que find() puede retornar undefined
const usuarios: Usuario[] = [];
const admin: Usuario = usuarios.find(u => u.rol === "admin");
// TS2322: Type 'Usuario | undefined' is not assignable to type 'Usuario'

// BIEN — manejar el caso undefined
const admin = usuarios.find(u => u.rol === "admin");
if (!admin) throw new Error("Admin no encontrado");
// Después de la guarda, TS sabe que admin es Usuario
```

### `TS2339: Property 'X' does not exist on type 'Y'`

**Causas comunes**:
1. Typo en el nombre de la propiedad
2. El tipo no tiene esa propiedad (usar `interface` correcta)
3. Acceso a propiedad opcional sin optional chaining

```typescript
// MAL
const nombre = usuario.nombe;  // typo: "nombe" vs "nombre"

// Caso con tipos de API externa
const data: unknown = await fetch("/api").then(r => r.json());
console.log(data.nombre);  // TS2339: unknown no tiene propiedades

// BIEN — validar con type guard o Zod
import { z } from "zod";
const UsuarioSchema = z.object({ nombre: z.string() });
const usuario = UsuarioSchema.parse(data);
console.log(usuario.nombre);  // ok: tipo inferido por Zod
```

---

## Errores de tsconfig.json

### `Cannot find module 'X' or its corresponding type declarations` (TS2307)

**Diagnóstico**:
```bash
# ¿Existe el paquete?
npm ls nombre-paquete

# ¿Existen los tipos?
npm ls @types/nombre-paquete

# ¿moduleResolution es correcto?
grep moduleResolution tsconfig.json
```

**Soluciones**:
1. Instalar tipos: `npm install -D @types/nombre-paquete`
2. Si no hay `@types/*`, crear declaración local:
   ```typescript
   // src/types/nombre-paquete.d.ts
   declare module "nombre-paquete" {
     export function metodo(): void;
   }
   ```
3. Verificar `moduleResolution` en tsconfig:
   ```json
   {
     "compilerOptions": {
       "moduleResolution": "bundler"  // para Vite/esbuild
       // o "node16" para Node.js puro
       // NUNCA "node" en proyectos nuevos (legacy)
     }
   }
   ```

### Path aliases no resuelven (`@app/`, `@shared/`)

```json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@app/*": ["src/app/*"],
      "@shared/*": ["src/shared/*"]
    }
  }
}
```

**Gotcha**: `tsc` resuelve los paths pero NO los transforma en el output.
El bundler (Vite, webpack) o `tsc-alias` deben resolver los paths en runtime.

```bash
# Para Vite — agregar resolve.alias en vite.config.ts
# Para Jest — agregar moduleNameMapper en jest.config.ts
# Para Node.js — usar tsc-alias como post-build step
npx tsc && npx tsc-alias
```

### `TS5023: Unknown compiler option 'X'`

**Causa**: opción de una versión más nueva de TypeScript en tsconfig.

```bash
# Verificar versión de TypeScript
npx tsc --version

# Opciones por versión:
# verbatimModuleSyntax — TS 5.0+
# moduleResolution: "bundler" — TS 5.0+
# resolvePackageJsonExports — TS 5.0+
```

**Solución**: actualizar TypeScript o quitar la opción incompatible.

---

## Errores de generics

### `TS2344: Type 'X' does not satisfy the constraint 'Y'`

```typescript
// MAL — el generic está restringido pero el tipo pasado no cumple
function primero<T extends { id: number }>(items: T[]): T {
  return items[0];
}
primero([{ nombre: "Ana" }]);  // error: falta 'id'

// BIEN
primero([{ id: 1, nombre: "Ana" }]);
```

### `TS2558: Expected 0 type arguments, but got 1`

**Causa**: pasar generics a una función que no los acepta.

```typescript
// MAL — useState ya infiere el tipo del valor inicial
const [count, setCount] = useState<number>(0);  // redundante pero válido

// Esto falla si la función no tiene parámetro de tipo:
fetch<Response>("/api");  // TS2558: fetch no acepta type arguments
```

---

## Errores de ESM vs CommonJS

### `ERR_REQUIRE_ESM: require() of ES Module not supported`

**Causa**: importar un paquete ESM-only desde un proyecto CommonJS.

```bash
# Diagnóstico: ver si el paquete es ESM-only
node -e "console.log(require.resolve('nombre-paquete'))"
# Si falla con ERR_REQUIRE_ESM, el paquete es ESM-only
```

**Soluciones**:
1. Migrar el proyecto a ESM (`"type": "module"` en package.json)
2. Usar `import()` dinámico en vez de `require()`:
   ```typescript
   const modulo = await import("paquete-esm");
   ```
3. Usar una versión anterior del paquete que soporte CJS (último recurso)

### `TS1479: ... resolves to an ESM-only module` con `moduleResolution: "node16"`

```json
{
  "compilerOptions": {
    "module": "node16",
    "moduleResolution": "node16"
  }
}
```

**Solución**: cambiar a `"moduleResolution": "bundler"` si usas Vite/esbuild,
o usar `import()` dinámico para paquetes ESM-only.

---

## Errores de bundlers (Vite, esbuild, webpack)

### Vite: `[plugin:vite:import-analysis] Failed to resolve import`

**Causas**:
1. Path alias no configurado en `vite.config.ts`
2. Extensión faltante en el import (Vite requiere extensión para CSS/assets)

```typescript
// vite.config.ts
import { defineConfig } from "vite";
import { resolve } from "path";

export default defineConfig({
  resolve: {
    alias: {
      "@": resolve(__dirname, "./src"),
    },
  },
});
```

### webpack: `Module not found: Error: Can't resolve 'X'`

```bash
# Diagnóstico
npx webpack --stats-error-details

# Soluciones comunes:
# 1. Agregar extensión a resolve.extensions en webpack.config
# 2. Agregar alias a resolve.alias
# 3. Instalar el loader correspondiente (ts-loader, babel-loader)
```

### esbuild: `No loader is configured for ".X" files`

```typescript
// esbuild necesita loaders explícitos para extensiones no estándar
import * as esbuild from "esbuild";
await esbuild.build({
  loader: {
    ".svg": "file",
    ".css": "css",
    ".png": "file",
  },
});
```

---

## Errores de declaration files (.d.ts)

### `TS7016: Could not find a declaration file for module 'X'`

```bash
# Opción 1: instalar tipos del DefinitelyTyped
npm install -D @types/nombre-paquete

# Opción 2: declaración local mínima
# src/types/nombre-paquete.d.ts
declare module "nombre-paquete";  # tipado como any — último recurso

# Opción 3: skipLibCheck (oculta errores, no los resuelve)
# tsconfig.json → "skipLibCheck": true
```

### Conflictos entre versiones de `@types/*`

```bash
# Diagnóstico
npm ls @types/react  # ver si hay múltiples versiones

# Solución: forzar una sola versión con overrides
# package.json
{
  "overrides": {
    "@types/react": "^18.2.0"
  }
}
```

---

## strict mode — errores al activar

Al migrar un proyecto a `"strict": true`, los errores más comunes:

| Error | Flag específico | Solución rápida |
|-------|----------------|-----------------|
| `TS7006: Parameter implicitly has 'any'` | `noImplicitAny` | Agregar tipo al parámetro |
| `TS2532: Object is possibly 'undefined'` | `strictNullChecks` | Optional chaining `?.` o guarda `if` |
| `TS2564: Property has no initializer` | `strictPropertyInitialization` | Inicializar o marcar con `!` (non-null assertion) |
| `TS7053: Element implicitly has 'any'` | `noImplicitAny` | Usar `Record<string, T>` o index signature |

**Estrategia de migración incremental**: activar flags uno a uno en vez de `strict: true`
de golpe. Empezar con `noImplicitAny`, luego `strictNullChecks`, luego el resto.

---

## Gotchas / Errores comunes no obvios

- **`tsc --noEmit` pasa localmente pero CI falla con TS2307 en el mismo archivo**: la versión de TypeScript en node_modules local difiere de la versión en CI. Causa: `typescript` está en `devDependencies` con rango `^5.0.0` y npm resolvió versiones distintas en los dos entornos. Solución: fijar la versión exacta en devDependencies (`"typescript": "5.3.3"` sin `^`) o usar `npm ci` con lockfile en CI.
- **Path alias `@app/*` resuelve en `tsc` pero falla en Jest con `Cannot find module '@app/...'`**: `tsc` maneja los aliases del tsconfig pero el runner de Jest no los conoce por defecto. Causa: Jest no lee `tsconfig.json` para resolución de módulos; necesita `moduleNameMapper` equivalente en `jest.config.ts`. Solución: agregar `moduleNameMapper: {"^@app/(.*)$": "<rootDir>/src/app/$1"}` al jest config, idéntico al paths del tsconfig.
- **`skipLibCheck: true` oculta errores que rompen el build en el servidor de CI del cliente**: el desarrollador activó `skipLibCheck` para silenciar errores de `@types/*` conflictivos sin resolver el conflicto real. Causa: múltiples versiones del mismo `@types/` paquete en el árbol de dependencias. Solución: usar `npm ls @types/react` para detectar duplicados y resolver con `overrides` en package.json — `skipLibCheck` debe ser temporal, no permanente.
- **`TS1259: Module can only be default-imported using 'esModuleInterop'`**: importar un módulo CommonJS con `import X from 'x'` cuando `esModuleInterop: false`. Causa: ausencia de `"esModuleInterop": true` en tsconfig. El gotcha es que activarlo solo resuelve el error de tsc pero no garantiza que el bundler produzca el import correcto. Solución: activar `esModuleInterop: true` junto con `allowSyntheticDefaultImports: true` y verificar que el bundler también tiene su equivalente configurado.

## Checklist de diagnóstico

- [ ] `npx tsc --version` — ¿versión compatible con las opciones de tsconfig?
- [ ] `npx tsc --noEmit` — ¿type-check pasa sin emitir?
- [ ] ¿`moduleResolution` es `bundler` (Vite/esbuild) o `node16` (Node.js)?
- [ ] ¿Los `@types/*` están instalados para paquetes sin tipos propios?
- [ ] ¿Path aliases configurados en tsconfig Y en el bundler/runner?
- [ ] ¿El proyecto es ESM (`"type": "module"`) o CJS? ¿Consistente con tsconfig?
- [ ] `npm ls --all | grep "deduped"` — ¿conflictos de versiones de tipos?
- [ ] Para errores de strict: ¿el flag específico que causa el error está identificado?
