Tips & Tricks (Actualizado: 3/6/2026)

Claude Code y TypeScript: consejos prácticos para avanzar rápido y seguro

Mejora TypeScript con Claude Code usando strict, Zod, Union, genéricos, satisfies y pruebas de tipos.

Claude Code y TypeScript: consejos prácticos para avanzar rápido y seguro

Claude Code acelera mucho el trabajo con TypeScript, sobre todo en formularios, helpers de API y pruebas. El riesgo es igual de claro: si los límites de tipos son vagos, también acelera los errores. Para empezar con buen pie, define las reglas de tipos antes de pedir la funcionalidad.

En este artículo, strict significa que TypeScript rechaza código sospechoso; los tipos de dominio son reglas del negocio escritas como tipos; una Union discriminada modela estados con formas distintas; y la validación en runtime comprueba datos mientras el programa se ejecuta. La idea no es escribir tipos complicados, sino dar a Claude Code menos margen para inventar atajos inseguros.

Dale primero un mapa de tipos

Antes del prompt largo, prepara un mapa pequeño: reglas del compilador, tipos de dominio, entradas externas, estados y pruebas de tipos. Ese mapa hace que el diff generado sea más fácil de revisar.

flowchart TD
  A["Requisito"] --> B["tsconfig: reglas strict"]
  B --> C["Tipos de dominio: Plan y Account"]
  C --> D["Datos externos: unknown y validación"]
  D --> E["Estado: Union discriminadas"]
  E --> F["Pruebas de tipos: expectTypeOf / tsd"]
  F --> G["Implementación y revisión con Claude Code"]

Usa documentación oficial como base: strict, noUncheckedIndexedAccess, exactOptionalPropertyTypes, Narrowing, Generics, Utility Types y la nota de satisfies. Para validar en runtime, consulta también la documentación de Zod.

Lecturas relacionadas: TypeScript Utility Types, TypeScript Generics y Zod Validation.

Empieza con un tsconfig estricto

No basta con decir “hazlo en TypeScript”. Primero fija el contrato del compilador.

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,
    "noImplicitOverride": true,
    "noFallthroughCasesInSwitch": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*.ts", "src/**/*.tsx", "tests/**/*.ts"]
}

Añade las restricciones al prompt.

Este repositorio usa TypeScript strict.
No introduzcas any. Trata las entradas externas como unknown y valídalas con Zod.
Cuando manejes Union en switch, añade una comprobación exhaustiva con never.
Después de implementar, ejecuta npx tsc --noEmit.

noUncheckedIndexedAccess mantiene visible la posibilidad de undefined al leer arrays y objetos. Es estricto, pero detecta campos ausentes de API, listas vacías y traducciones incompletas antes de producción.

Caso 1: modelar planes SaaS como tipos de dominio

Los tipos de dominio convierten reglas del negocio en TypeScript. Planes, permisos, facturas y estados de publicación deberían existir antes de la UI.

export type Plan = "free" | "pro" | "enterprise";

export type Account = {
  id: string;
  email: string;
  plan: Plan;
  seats: number;
  trialEndsAt: string | null;
};

export type CreateAccountInput = {
  email: string;
  plan: Exclude<Plan, "enterprise">;
  seats?: number;
};

export type UpdateAccountInput = Partial<
  Pick<Account, "email" | "plan" | "seats" | "trialEndsAt">
>;

Exclude elimina miembros de una Union. Partial vuelve opcionales las propiedades; sirve para actualizaciones, pero puede relajar demasiado una entrada de creación.

Caso 2: validar datos de API desde unknown

Los tipos de TypeScript desaparecen en runtime. APIs, formularios, cookies, localStorage, CSV y salidas de IA pueden venir rotos. Recíbelos como unknown, valida y usa el resultado tipado.

npm install zod
import { z } from "zod";

const AccountSchema = z.object({
  id: z.string().min(1),
  email: z.string().email(),
  plan: z.enum(["free", "pro", "enterprise"]),
  seats: z.number().int().positive(),
  trialEndsAt: z.string().datetime().nullable()
});

type Account = z.infer<typeof AccountSchema>;

export function parseAccountResponse(json: unknown): Account {
  return AccountSchema.parse(json);
}

unknown significa que aún no has demostrado qué es el valor. A diferencia de any, obliga a validar antes de leer propiedades.

Caso 3: cerrar el estado de pago con Union

Pagos, subidas, formularios y jobs son máquinas de estado. Evita status: string; permite estados imposibles.

type PaymentResult =
  | { status: "pending"; invoiceId: string }
  | { status: "paid"; invoiceId: string; paidAt: string }
  | { status: "failed"; invoiceId: string; reason: string };

export function renderPaymentMessage(result: PaymentResult): string {
  switch (result.status) {
    case "pending":
      return `Invoice ${result.invoiceId} is waiting for payment.`;
    case "paid":
      return `Invoice ${result.invoiceId} was paid at ${result.paidAt}.`;
    case "failed":
      return `Invoice ${result.invoiceId} failed: ${result.reason}.`;
    default: {
      const exhaustive: never = result;
      return exhaustive;
    }
  }
}

La rama never obliga a cubrir todos los estados válidos. Si más tarde aparece refunded, TypeScript pedirá el nuevo caso.

Caso 4: genéricos y satisfies

Los genéricos permiten reutilizar helpers sin perder el tipo concreto de cada llamada.

export function groupBy<T, K extends PropertyKey>(
  items: readonly T[],
  getKey: (item: T) => K
): Partial<Record<K, T[]>> {
  const grouped: Partial<Record<K, T[]>> = {};

  for (const item of items) {
    const key = getKey(item);
    const bucket = grouped[key] ?? [];
    bucket.push(item);
    grouped[key] = bucket;
  }

  return grouped;
}

const accounts = [
  { id: "a1", plan: "free" },
  { id: "a2", plan: "pro" },
  { id: "a3", plan: "pro" }
] as const;

const byPlan = groupBy(accounts, (account) => account.plan);
const proAccounts = byPlan.pro ?? [];

console.log(proAccounts.map((account) => account.id));

Para objetos de configuración, satisfies suele ser mejor que una assertion amplia.

type ApiRoute = {
  method: "GET" | "POST" | "PATCH" | "DELETE";
  path: `/${string}`;
  auth: boolean;
};

const routes = {
  listAccounts: { method: "GET", path: "/accounts", auth: true },
  createAccount: { method: "POST", path: "/accounts", auth: true },
  healthCheck: { method: "GET", path: "/health", auth: false }
} as const satisfies Record<string, ApiRoute>;

type RouteName = keyof typeof routes;

export function getRoute(name: RouteName) {
  return routes[name];
}

Añade pruebas de tipos

Los tipos públicos importantes también necesitan pruebas.

npm install -D vitest tsd
import { expectTypeOf, test } from "vitest";

type CreateAccountInput = {
  email: string;
  plan: "free" | "pro";
  seats?: number;
};

test("CreateAccountInput keeps the public API narrow", () => {
  expectTypeOf<CreateAccountInput>().toMatchTypeOf<{
    email: string;
    plan: "free" | "pro";
    seats?: number;
  }>();
});

Usos reales y errores comunes (Use case / Pitfall checklist)

Caso de usoLo que fijan los tiposLo que genera Claude Code
Facturación SaaSplanes, facturas, permisosramas de UI, formularios, mensajes
Panel admin con APIschemas Zod, tipos de respuestafetch, tablas, estados de carga
CMS de artículosslug, idioma, estado, imagen principalborradores MDX, listados, validaciones
Formulario de contactoschema de entrada, Union de resultadoUI, envío, cobertura Vitest
ErrorConsecuenciaSolución
Respuesta API como anyJSON roto compilaunknown y Zod
status: stringestados imposiblesUnion discriminada
Muchos as Userse ocultan erroresschema, type guards, satisfies
Partial<T> para crearcampos obligatorios pasan a opcionalesseparar create y update
Sin pruebas de tiposlos tipos públicos se ensanchanexpectTypeOf o tsd

En ClaudeCodeLab, Masa vio URLs de locales inválidos cuando lang estaba tipado como string. Cerrar el tipo a una Union concreta hizo que las ediciones de Claude Code fueran mucho más predecibles.

Reglas y CTA

## TypeScript rules
- Use strict TypeScript.
- Do not introduce `any`. Use `unknown` at external boundaries.
- Prefer discriminated unions for states.
- Prefer `satisfies` over broad type assertions.
- Derive API types from Zod schemas when runtime data is involved.
- Add Vitest or tsd style type checks for exported helper types.
- Run `npx tsc --noEmit` before reporting completion.

Para proyectos personales, el catálogo de productos reúne plantillas y checklists para flujos con Claude Code. Para equipos, la formación y consultoría de Claude Code puede cubrir migración a strict, límites con Zod, pruebas de tipos y reglas de CLAUDE.md en un repositorio real.

Resultado de la prueba

Probé este flujo en un proyecto TypeScript pequeño: cambié respuestas API de any a unknown con Zod y pedí a Claude Code que añadiera ramas Union y pruebas expectTypeOf. El resultado útil fue detectar estados no manejados y accesos a propiedades inexistentes antes de la revisión.

#Claude Code #TypeScript #type safety #development efficiency #frontend
Gratis

PDF gratis: cheatsheet de Claude Code

Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.

Cuidamos tus datos y no enviamos spam.

Masa

Sobre el autor

Masa

Ingeniero enfocado en workflows prácticos con Claude Code.