Cuando trabajamos con genéricos en TypeScript, una de las preguntas que surge rápidamente es cómo limitar los tipos que podemos pasar a esos genéricos para que cumplan ciertas condiciones o pertenezcan a una jerarquía concreta. Esto es especialmente útil cuando queremos que nuestro código sea más seguro y que el autocompletado nos ayude a escribirlo mejor.
Imaginemos que estamos diseñando una API para una red social y tenemos diferentes tipos de publicaciones: notas, notas coloridas, fotos y vídeos. En lugar de permitir que el genérico acepte cualquier tipo, podemos crear una jerarquía de interfaces para organizar estos tipos. Por ejemplo, definimos una interfaz común llamada Post y hacemos que todas las demás interfaces, como Nota, NotaColorida, Foto y Vídeo, extiendan de Post. Así, establecemos una relación clara entre ellas.
interface Post {
id: number;
fecha: Date;
}
interface Nota extends Post {
contenido: string;
}
interface NotaColorida extends Nota {
color: string;
}
interface Foto extends Post {
url: string;
}
interface Vídeo extends Post {
duracion: number;
}
Una vez que tenemos esta jerarquía, podemos restringir el tipo genérico para que solo acepte tipos que extiendan de Post. Esto se hace usando la palabra clave extends en la definición del genérico. Por ejemplo, si tenemos una función que recibe un parámetro genérico P, podemos escribirla así:
function publicar<P extends Post>(publicacion: P) {
console.log(publicacion.id);
// Aquí podemos acceder a las propiedades comunes de Post
}
Con esta restricción, TypeScript nos asegura que cualquier tipo que pasemos como argumento debe tener al menos las propiedades definidas en Post. Si intentamos pasar un número o cualquier otro tipo que no cumpla con esta interfaz, obtendremos un error de compilación.
Es importante destacar que la restricción no es una garantía absoluta en tiempo de ejecución, sino una verificación estática que hace el compilador. Por ejemplo, si Post solo tiene un método toString, cualquier tipo que tenga ese método podría ser considerado válido, incluso si no es lo que realmente queremos. Por eso, debemos diseñar bien nuestras interfaces para que reflejen correctamente las propiedades y métodos que queremos exigir.
Además, esta restricción mejora el autocompletado en los editores de código, ya que al saber que P extiende de Post, el editor puede sugerirnos las propiedades comunes que podemos usar sin miedo a errores.
En resumen, crear jerarquías de interfaces y usar extends para restringir tipos genéricos nos ayuda a escribir código más robusto y mantenible, evitando que se pasen tipos no deseados y facilitando el trabajo con las propiedades comunes de esos tipos.