Varians beskriver, hvordan subtypning af en sammensat type relaterer til subtypning af dens dele — dvs. hvornår er Container<Sub> tildelt til Container<Super>?
Lad Dog være en undertype af Animal.
let dogs: Dog[] = [];
let animals: Animal[] = dogs; // ✅ Dog[] is assignable to Animal[]
Retur typer og arrays er kovariante: hvis Dog ⊆ Animal, så er Dog[] ⊆ Animal[]. En funktion, der returnerer Dog, kan bruges, hvor en der 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
Funktions parametre er kontravariante: Handler<Animal> kan tildeles til Handler<Dog>, det modsatte af elementforholdet. Dette er korrekt — noget, der håndterer alle dyr, håndterer helt sikkert hunde.
// Method parameters in TS are bivariant by default (a known unsound convenience)
interface Comparer<T> { compare(a: T): void; }
TypeScript checker selvstændige funktionstyper kontravariant kun under strictFunctionTypes; metodeparametre er bevidst bivariante af ergonomiske grunde, hvilket er teknisk usikkert.
Varians forklarer hvorfor visse tildelinger er tilladt eller afvist — hvorfor Dog[] passer til Animal[], men et (d: Dog) => void callback ikke altid kan stå i stedet for (a: Animal) => void.