Ponle fecha de vencimiento a cada supresión: ts-expect-error en vez de ts-ignore
// @ts-ignore esconde bugs. // @ts-expect-error los hace vencer. Ambos silencian un error de TypeScript en la línea siguiente, pero solo uno te avisa cuándo ese silencio ya no hace falta. Esa única diferencia es la razón por la que el segundo pertenece a tu código y el primero pertenece al pasado.
Por qué ts-ignore se pudre
Un comentario // @ts-ignore suprime el error que esté en la línea siguiente, y lo sigue haciendo para siempre. Corregís el bug de fondo, actualizás la librería, afinás el tipo: al comentario no le importa. Se queda ahí, callado, sin esconder nada. Ahora cada lector tiene que preguntarse: ¿esta supresión sigue siendo necesaria, o es peso muerto que además está tapando un error nuevo que se coló en esa línea? No podés saberlo sin borrarlo y volver a compilar, así que nadie lo hace. Las supresiones se acumulan, y cada una es un lugar donde al chequeador de tipos se le ordenó mirar para otro lado de forma permanente.
Cómo lo resuelve ts-expect-error
// @ts-expect-error hace la misma supresión con una regla extra: si la línea siguiente no tiene error, TypeScript reporta Unused '@ts-expect-error' directive. El comentario ahora es una afirmación —"acá hay un error"— que el compilador verifica en cada build.
// @ts-expect-error — upstream types are wrong, see issue #421
const total = sum(values, { strict: true });
Corregís el problema real y la línea deja de dar error. Al instante, el propio @ts-expect-error empieza a dar error, avisándote que lo borres. La supresión se limpia sola. No puede sobrevivir al problema para el que se escribió, y nunca puede tapar en silencio un error distinto, porque el desajuste aparece apenas el error esperado se mueve o desaparece.
Cuándo usar cuál
| Situación | Directiva |
|---|---|
| Error conocido y temporal que vas a revisar | // @ts-expect-error + motivo |
| Error que una corrección/actualización va a eliminar | // @ts-expect-error + motivo |
| "Que compile y ya" sin plan de seguimiento | Corregí el tipo en su lugar |
| Suprimir un error en un archivo entero | Ninguno — acotá el alcance |
La regla práctica: usá @ts-expect-error por defecto. Cada uno que escribís trae su propio chequeo de vencimiento. Reservá @ts-ignore para el caso raro en que un error es genuinamente intermitente entre entornos y una afirmación dura de "debe dar error" rompería el build — e incluso ahí, comentá por qué.
Jugada avanzada: hacela cumplir con un linter
No dependas de la disciplina. La regla @typescript-eslint/ban-ts-comment de typescript-eslint lo hace de forma mecánica. Sus valores por defecto recomendados prohíben @ts-ignore por completo (ts-ignore: true) y permiten @ts-expect-error solo con una descripción ("allow-with-description"), con un minimumDescriptionLength de 3 caracteres. El preset estricto sube ese mínimo a 10 caracteres.
Podés ir más lejos con descriptionFormat, un regex que impone un estilo de casa a cada justificación — por ejemplo exigir ^: TS\d+ because .+$ para que cada supresión nombre el código de error y el motivo. Activalo y tu CI rechaza un @ts-ignore pelado y un @ts-expect-error sin motivo antes de que se mergeen.
Otro dato útil: desde TypeScript 5.5, @ts-expect-error también funciona en la línea de arriba de una expresión JSX/TSX, y una descripción después de la directiva es texto libre que el compilador ignora — así que escribila para humanos y dejá que el linter controle su forma.
La conclusión
@ts-ignore es una supresión sin fecha de vencimiento. @ts-expect-error es una supresión que se borra sola cuando deja de ser cierta. Cambialos en todos lados, exigí un motivo, y dejá que el compilador te avise cuándo es seguro limpiar.
Recursos
- Notas de la versión TypeScript 3.9 —
@ts-expect-error - typescript-eslint — regla
ban-ts-comment - TypeScript Handbook — índice de notas de versión
¿Estás enviando TypeScript escrito por IA? Yeda AI audita y endurece los códigos que producen los agentes de programación.