Tipos condicionales con Typescript y Zod

Aprende a usar tipos condicionales con Typescript y Zod para validar datos en tu aplicación. Hay veces que dos tipos de datos tienen propiedades en común. En estos casos, es conveniente saber cómo validarlos de forma dinámica y sin repetir código. En este artículo aprenderás a hacerlo con Typescript y Zod.

En este artículo aprenderás:

  1. ¿Qué es un tipo condicional?
  2. Ejemplo con Typescript
  3. ¿Cómo usar tipos condicionales con Zod?

¿Qué es un tipo condicional?

Un tipo condicional te permite definir diferentes estructuras o reglas de tipado dependiendo de ciertas propiedades en tus tipos. Esto puede ser útil para crear tipados más flexibles y adaptables a diferentes situaciones.

Ejemplo con Typescript

Imagina que tienes dos tipos de objeto diferentes que comparten algunas propiedades en común. Por ejemplo, un tipo Tenista y un tipo Futbolista. Ambos tienen una propiedad nombre y una propiedad edad. Sin embargo, los futbolistas tienen una propiedad posicion y las propiedad club, mientras que los tenistas tienen una propiedad ranking y una propiedad pais. Ambos tipos de objeto tienen propiedades en común, pero también tienen propiedades que son únicas para cada uno.

En este caso tenemos las siguientes 3 opciones viables:

  1. Crear un tipo Deportista con todas las propiedades de ambos tipos y hacerlas opcionales.
  2. Crear un tipo Futbolista con todas las propiedades de un futbolista y hacer lo mismo con el tipo Tenista.
  3. Crear un tipo Deportista que tenga todas las propiedades de ambos tipos y agregar condicionalmente las propiedades dinámicas de cada tipo de deportista (Futbolista o Tenista).

Opción 1:

type Deportista = {
  nombre: string;
  edad: number;
  posicion?: string;
  club?: string;
  ranking?: number;
  pais?: string;
};

Ventajas: Una sola interfaz para ambos tipos de deportistas.
Desventajas: No existe un tipado estricto para cada tipo de deportista. Podría haber un deportista que tenga una propiedad posicion y una propiedad ranking al mismo tiempo y Typescript no lo detectaría como un error.

Opción 2:

type Futbolista = {
  nombre: string;
  edad: number;
  posicion: string;
  club: string;
};

type Tenista = {
  nombre: string;
  edad: number;
  ranking: number;
  pais: string;
};

Ventajas: El tipado es más estricto y no permite que un deportista tenga propiedades de otro tipo de deportista.
Desventajas: Hay código repetido entre ambos tipos de deportistas.

Opción 3:

type Futbolista = {
  posicion: string;
  club: string;
}

type Tenista = {
  ranking: number;
  pais: string;
}

type Deportista = {
  nombre: string;
  edad: number;
} & (Futbolista | Tenista); 

Ventajas: El tipado es estricto y no permite que un deportista tenga propiedades de otro tipo de deportista. Al mismo tiempo permite reusar código entre ambos tipos de deportistas.
Desventajas: Es posible que sea un poco más difícil de entender para alguien que no esté familiarizado con los tipos condicionales.

¿Cómo usar tipos condicionales con Zod?

Zod es una librería de validación de datos que te permite validar datos en tu aplicación. Puedes usarla para validar datos en tu frontend o en tu backend. Zod tiene una API muy sencilla y fácil de usar. Puedes leer más acerca de Zod en su documentación oficial.

Imagina que tenemos el mismo ejemplo:

Tienes dos tipos de objeto diferentes que comparten algunas propiedades en común. Por ejemplo, un tipo Tenista y un tipo Futbolista. Ambos tienen una propiedad nombre y una propiedad edad. Sin embargo, los futbolistas tienen una propiedad posicion y las propiedad club, mientras que los tenistas tienen una propiedad ranking y una propiedad pais. Ambos tipos de objeto tienen propiedades en común, pero también tienen propiedades que son únicas para cada uno.

En este caso tenemos las siguientes 3 opciones viables:

  1. Crear un tipo Deportista con todas las propiedades de ambos tipos y hacerlas opcionales.
  2. Crear un tipo Futbolista con todas las propiedades de un futbolista y hacer lo mismo con el tipo Tenista.
  3. Crear un tipo Deportista que tenga todas las propiedades de ambos tipos y agregar condicionalmente las propiedades dinámicas de cada tipo de deportista (Futbolista o Tenista).

Opción 1:

const Deportista = z.object({
  nombre: z.string(),
  edad: z.number(),
  posicion: z.string().optional(),
  club: z.string().optional(),
  ranking: z.number().optional(),
  pais: z.string().optional(),
});

Ventajas: Una sola interfaz para ambos tipos de deportistas.
Desventajas: No existe un tipado estricto para cada tipo de deportista. Podría haber un deportista que tenga una propiedad posicion y una propiedad ranking al mismo tiempo y Typescript no lo detectaría como un error.

Opción 2:

const Futbolista = z.object({
  nombre: z.string(),
  edad: z.number(),
  posicion: z.string(),
  club: z.string(),
});

const Tenista = z.object({
  nombre: z.string(),
  edad: z.number(),
  ranking: z.number(),
  pais: z.string(),
});

Ventajas: El tipado es más estricto y no permite que un deportista tenga propiedades de otro tipo de deportista.
Desventajas: Hay código repetido entre ambos tipos de deportistas.

Opción 3:

const futbolista = z.object({
  posicion: z.string(),
  club: z.string(),
});

const tenista = z.object({
  ranking: z.number(),
  pais: z.string(),
});

const deportistaBase = z.object({
  nombre: z.string(),
  edad: z.number(),
})

const deportistaFutbolista = deportistaBase.merge(futbolista);
const deportistaTenista = deportistaBase.merge(tenista);
const deportista = z.union([deportistaFutbolista, deportistaTenista]);

Ventajas: El tipado es estricto y no permite que un deportista tenga propiedades de otro tipo de deportista. Al mismo tiempo permite reusar código entre ambos tipos de deportistas.
Desventajas: Es posible que sea un poco más difícil de entender para alguien que no esté familiarizado con los tipos condicionales en zod.

Conclusión

Los tipos condicionales son una herramienta muy útil para validar datos en tu aplicación. Te permiten crear tipos de datos más flexibles y adaptables a diferentes situaciones. En este artículo aprendiste a usarlos con Typescript y Zod. Espero que te haya gustado y que te sea útil en tu día a día.

Ayúdame a mejorar este artículo

¿Quisieras complementar este artículo o encontraste algún error?¡Excelente! Envíame un correo.

  • seb@sebastianfdz.com