Introducción: «Type 'string | undefined' is not assignable to type 'string'» — ¿un dolor familiar?
\n\nSi llevas al menos una semana escribiendo en TypeScript, seguramente has visto este mensaje. Aparece en el momento más inesperado: estás seguro de que la variable es una cadena, pero el compilador insiste obstinadamente: «¡Oye, ahí puede haber undefined!». ¿Te suena?
Este error es una de las preguntas más frecuentes en Stack Overflow (miles de visitas, decenas de respuestas). Y no es que TypeScript «se equivoque». Al contrario: te está salvando de errores en tiempo de ejecución que podrían tumbar la aplicación. Pero, ¿cómo explicarle esto al compilador? ¿Cómo hacer que el código sea seguro y legible a la vez?
\n\nEn este artículo analizaremos:
\n- \n
- Por qué ocurre el error
Type 'string | undefined' is not assignable to type 'string'\n - 5 formas prácticas de solucionarlo (de simples a avanzadas) \n
- Trampas típicas para principiantes \n
- Cuándo usar
!(non-null assertion) y cuándo es mejor??(nullish coalescing) \n
¿Listos? ¡Allá vamos!
\n\n1. ¿Por qué ocurre este error en TypeScript?
\n\nEn JavaScript, una variable puede ser undefined en cualquier momento. TypeScript, especialmente con la bandera strictNullChecks activada, quiere que indiques explícitamente: «Sé que aquí puede haber un valor nulo, y estoy trabajando con eso».
Mira este ejemplo simple:
\n\nfunction getUsername(id: number): string {\n const user = users.find(u => u.id === id);\n return user.name; // ¡Error! user puede ser undefined\n}\n\n\nEl método find() devuelve User | undefined. Si no se encuentra el usuario, devolverá undefined. TypeScript lo ve y grita: «¡Estás intentando asignar string | undefined a string! ¡No puedes!».
Esto no es un error de TypeScript, es una característica. Te obliga a pensar: «¿Y si el usuario no existe? ¿Qué devolverá la función? ¿Una cadena vacía? ¿Lanzará un error?». Y eso está bien.
\n\n2. 5 formas de solucionar el error (de simple a complejo)
\n\n2.1. Operador de aserción no nula (!)
\n\nLa forma más rápida (y más peligrosa) es decirle a TypeScript: «Cállate, sé lo que hago».
\n\nfunction getUsername(id: number): string {\n const user = users.find(u => u.id === id);\n return user!.name; // ! — estoy seguro de que user no es undefined\n}\n\n\nCuándo usarlo: Solo si estás absolutamente seguro de que el valor existe. Por ejemplo, si acabas de agregar este usuario al array y sabes con certeza que find lo encontrará.
Cuándo NO usarlo: En el 90% de los casos. Es como desconectar la bolsa de aire en un coche: funciona, pero el riesgo es enorme.
\n\n2.2. Verificación con if (type guard)
\n\nLa forma clásica y segura:
\n\nfunction getUsername(id: number): string {\n const user = users.find(u => u.id === id);\n if (user) {\n return user.name; // TypeScript sabe: dentro del bloque user es definitivamente User\n }\n return 'Invitado'; // fallback\n}\n\n\nTypeScript es inteligente: después de la verificación if (user), «reduce» el tipo. Dentro del bloque, user es User, no User | undefined.
2.3. Operador de encadenamiento opcional (?.) con fallback
\n\nUna elegante línea única para trabajar con objetos anidados:
\n\nfunction getUsername(id: number): string {\n const user = users.find(u => u.id === id);\n return user?.name ?? 'Invitado';\n}\n\n\nAnalicemos en detalle:
\n- \n
user?.name— siuseresundefined, devuelveundefinedsin lanzar un error \n ?? 'Invitado'— si el valor de la izquierda esundefinedonull, se sustituye por 'Invitado'