La varianza describe cómo se relaciona el subtipado de un tipo compuesto con el subtipado de sus partes — es decir, ¿cuándo es Container<Sub> asignable a Container<Super>?
Sea Dog un subtipo de .
La varianza describe cómo se relaciona el subtipado de un tipo compuesto con el subtipado de sus partes — es decir, ¿cuándo es Container<Sub> asignable a Container<Super>?
Sea Dog un subtipo de .
Animallet dogs: Dog[] = [];
let animals: Animal[] = dogs; // ✅ Dog[] is assignable to Animal[]
Los tipos de retorno y los arrays son covariantes: si Dog ⊆ Animal, entonces Dog[] ⊆ Animal[]. Una función que retorna Dog se puede usar donde se espera una que retorna Animal.
type Handler<T> = (arg: T) => void;
let animalHandler: Handler<Animal> = (a) => {};
let dogHandler: Handler<Dog> = animalHandler; // ✅ (with strictFunctionTypes)
// a handler that accepts ANY Animal can safely handle a Dog
Los parámetros de función son contravariantes: Handler<Animal> es asignable a Handler<Dog>, lo inverso de la relación entre los elementos. Esto es sólido (sound): algo que maneja todos los animales ciertamente maneja perros.
// Method parameters in TS are bivariant by default (a known unsound convenience)
interface Comparer<T> { compare(a: T): void; }
TypeScript comprueba los tipos de función independientes de forma contravariante solo bajo strictFunctionTypes; los parámetros de método son intencionalmente bivariantes por ergonomía, lo que es técnicamente poco sólido.
La varianza explica por qué ciertas asignaciones se permiten o se rechazan — por qué Dog[] encaja en Animal[] pero un callback (d: Dog) => void no siempre puede reemplazar a (a: Animal) => void.
Entenderla te ayuda a diseñar APIs genéricas (por ejemplo, posiciones de solo lectura frente a posiciones de escritura) y a descifrar confusos errores de "not assignable" relacionados con funciones y genéricos.