Varians beskriver hvordan subtypifisering av en kompositt type forholder seg til subtypifisering av delene — dvs. når er Container<Sub> tildelbar til Container<Super>?
La Dog være en subtype av Animal.
let dogs: Dog[] = [];
let animals: Animal[] = dogs; // ✅ Dog[] is assignable to Animal[]
Returntyper og arrayer er kovariante: hvis Dog ⊆ Animal, så Dog[] ⊆ Animal[]. En funksjon som returnerer Dog kan brukes der en som returnerer Animal forventes.
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
Funksjonsparametere er kontravariante: Handler<Animal> er tildelbar til Handler<Dog>, det motsatte av elementforholdet. Dette er forsvarlig — noe som håndterer alle dyr håndterer absolutt hunder.
// Method parameters in TS are bivariant by default (a known unsound convenience)
interface Comparer<T> { compare(a: T): void; }
TypeScript sjekker standalone funksjonstyper kontravariante bare under strictFunctionTypes; metodeparametere er med vilje bivariante for ergonomi, noe som teknisk sett er usundt.
Varians forklarer hvorfor visse tildelinger er tillatt eller avslått — hvorfor Dog[] passer til Animal[] men en (d: Dog) => void callback ikke alltid kan erstatte en (a: Animal) => void.
Å forstå det hjelper deg å designe generiske API-er (f.eks. skrivebeskyttet vs skrivbare posisjoner) og dekode forvirrende "not assignable"-feil som involverer funksjoner og generika.