Varian menjelaskan bagaimana subtipe tipe komposit berhubungan dengan subtipe bagian-bagiannya — yaitu, kapan Container<Sub> dapat ditetapkan ke Container<Super>?
Misalkan Dog adalah subtipe dari Animal.
let dogs: Dog[] = [];
let animals: Animal[] = dogs; // ✅ Dog[] is assignable to Animal[]
Tipe pengembalian dan larik adalah kovarian: jika Dog ⊆ Animal, maka Dog[] ⊆ Animal[]. Fungsi yang mengembalikan Dog dapat digunakan di mana pengembalian Animal diharapkan.
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
Parameter fungsi adalah kontravarian: Handler<Animal> dapat ditetapkan ke Handler<Dog>, kebalikan dari hubungan elemen. Ini konsisten — sesuatu yang menangani semua hewan pasti menangani anjing.
// Method parameters in TS are bivariant by default (a known unsound convenience)
interface Comparer<T> { compare(a: T): void; }
TypeScript memeriksa tipe fungsi mandiri secara kontravarian hanya di bawah strictFunctionTypes; parameter metode sengaja bivarian untuk ergonomi, yang secara teknis tidak konsisten.
Varian menjelaskan mengapa penetapan tertentu diizinkan atau ditolak — mengapa Dog[] cocok untuk Animal[] tetapi callback (d: Dog) => void tidak selalu dapat menggantikan (a: Animal) => void.
Memahaminya membantu Anda merancang API generik (misalnya posisi hanya-baca vs penulisan) dan mendekodekan kesalahan "tidak dapat ditetapkan" yang membingungkan yang melibatkan fungsi dan generik.