Domina los Tipos Condicionales en TypeScript

¡Ah, los tipos condicionales en TypeScript... Son como camaleones, cambian de forma y se adaptan a las necesidades de tu código! Quizás ya conozcas los tipos básicos, pero con los tipos condicionales, pasamos a un nivel superior. Imagina tipos inteligentes que se adaptan a la situación, como superhéroes del tipado. ¡Ponte cómodo y prepárate para añadir un poco de magia a tu código TypeScript! 🧙‍♂️

¿Por qué usar tipos condicionales? 🧐

En TypeScript, nos encanta cuando todo está bien ordenado y bien tipado. Pero a veces, nuestro código necesita un tipo que se adapte según ciertas condiciones. Imagina que tienes una función que puede devolver un string o un number, dependiendo de los parámetros de entrada. 😱 ¡Sin tipos condicionales, tendríamos que manejar cada caso manualmente, y eso se vuelve tedioso rápidamente! Afortunadamente, los tipos condicionales están aquí para aportar flexibilidad y reactividad, como un ninja del tipado. 🥷

Lo básico: sintaxis de tipos condicionales 🧩

Los tipos condicionales son como un operador ternario, pero para tipos. Aquí tienes un ejemplo para abrir el apetito:

typescript
1type IsString<T> = T extends string ? 'Es una cadena' : 'No es una cadena';

En este ejemplo, IsString es un tipo condicional que verifica si T es un string. Si es así, devuelve "Es una cadena", si no, "No es una cadena". Es simple, ¡pero espera a ver lo que podemos hacer en casos más avanzados!

Caso práctico: adaptar un tipo según la configuración 🛠️

Imaginemos una función que toma un parámetro de configuración y debe devolver un tipo diferente según esta configuración. ¡Los tipos condicionales son perfectos para este tipo de magia ✨!

Ejemplo de código

typescript
1type Config = {
2 mode: 'simple' | 'detallado';
3};
4
5type Response<T extends Config> = T['mode'] extends 'simple'
6 ? { data: string }
7 : { data: string; details: string[] };
8
9function fetchData<T extends Config>(config: T): Response<T> {
10 if (config.mode === 'simple') {
11 return { data: 'Datos simplificados' } as Response<T>;
12 } else {
13 return {
14 data: 'Datos completos',
15 details: ['detalle1', 'detalle2'],
16 } as Response<T>;
17 }
18}
19
20const simpleConfig = { mode: 'simple' };
21const detailedConfig = { mode: 'detallado' };
22
23const resultSimple = fetchData(simpleConfig); // { data: "Datos simplificados" }
24const resultDetailed = fetchData(detailedConfig); // { data: "Datos completos", details: [...] }

En este ejemplo, Response<T> adapta el tipo según si mode es "simple" o "detallado". La magia ocurre: fetchData(simpleConfig) devuelve un objeto solo con data, mientras que fetchData(detailedConfig) incluye también details. ¿Práctico, verdad?

Tipos condicionales anidados: tipado a la carta 🧇

¿Por qué detenerse ahí? ¡También puedes anidar tipos condicionales para manejar casos aún más específicos! Imagina que quieres adaptar el tipo no solo según el mode, sino también según si el usuario está autenticado o no. ¿Listo para ver acrobacias tipográficas? 🎢

typescript
1type UserResponse<
2 T extends Config,
3 Authenticated extends boolean,
4> = Authenticated extends true
5 ? T['mode'] extends 'simple'
6 ? { data: string }
7 : { data: string; details: string[] }
8 : { error: 'No autenticado' };
9
10function fetchUserData<T extends Config, Authenticated extends boolean>(
11 config: T,
12 isAuthenticated: Authenticated,
13): UserResponse<T, Authenticated> {
14 if (!isAuthenticated) {
15 return { error: 'No autenticado' } as UserResponse<T, Authenticated>;
16 }
17 if (config.mode === 'simple') {
18 return { data: 'Datos simplificados' } as UserResponse<T, Authenticated>;
19 } else {
20 return {
21 data: 'Datos completos',
22 details: ['detalle1', 'detalle2'],
23 } as UserResponse<T, Authenticated>;
24 }
25}
26
27const resultAuthSimple = fetchUserData(simpleConfig, true); // { data: "Datos simplificados" }
28const resultAuthDetailed = fetchUserData(detailedConfig, true); // { data: "Datos completos", details: [...] }
29const resultNotAuth = fetchUserData(detailedConfig, false); // { error: "No autenticado" }

Aquí, UserResponse adapta el tipo según dos criterios: mode y isAuthenticated. ¡El resultado es un tipado ultra-preciso que cubre todos los casos posibles!

Tipos condicionales avanzados con infer: deducción de tipos 🕵️‍♂️

¿Listo para un pequeño truco de magia? TypeScript ofrece una palabra clave especial en los tipos condicionales: infer. Con ella, puedes deducir un tipo directamente en tu tipo condicional. ¡Útil para extraer información de tipos complejos!

Ejemplo con infer

typescript
1type ReturnTypeOfFunction<T> = T extends (...args: any[]) => infer R
2 ? R
3 : never;
4
5function getHello(): string {
6 return '¡Hola, mundo!';
7}
8
9type HelloReturnType = ReturnTypeOfFunction<typeof getHello>; // Resultado: string

Aquí, ReturnTypeOfFunction usa infer R para deducir el tipo de retorno de una función. En este ejemplo, HelloReturnType será de tipo string, ya que getHello devuelve una cadena de caracteres.

Conclusión 🎉

Los tipos condicionales en TypeScript son como un superpoder para tu código. Te permiten crear tipos dinámicos y mantener un tipado riguroso, mientras mantienes el código ligero. Entonces, ¿listo para impresionar a tus colegas? ¡Experimenta con estos tipos condicionales y descubre nuevas formas de estructurar tu código TypeScript! 🚀

¡No más excusas para tipos aproximados: con los tipos condicionales, tu código TypeScript se vuelve simplemente infalible! 👌

Comparte este artículo


Sébastien Timoner

Sébastien TIMONER

Desarrollador Líder
Experto en Desarrollo a Medida
Aix-en-Provence, France

Experto en desarrollo web y gestión de equipos técnicos, me especializo en la creación y optimización de soluciones digitales de alto rendimiento. Gracias a un profundo dominio de tecnologías modernas como React.js, Node.js, TypeScript y Symfony, garantizo el éxito de proyectos SaaS complejos, desde el diseño hasta la implementación, para empresas de diversos sectores, dentro de offroadLabs.

En offroadLabs, ofrezco servicios de desarrollo a medida, combinando experiencia técnica y enfoque colaborativo. Ya sea para crear una solución SaaS innovadora, modernizar una aplicación existente o acompañar el desarrollo de habilidades de un equipo, me comprometo a proporcionar soluciones robustas y eficientes, adaptadas a las necesidades específicas de cada proyecto.

Estoy disponible para proyectos en la zona de Aix-en-Provence o en modalidad totalmente remota.