Variance menerangkan bagaimana subtaip sesuatu jenis komposit berkait dengan subtaip bahagian-bahagiannya — iaitu bilakah Container<Sub> boleh ditetapkan kepada Container<Super>?
Anggap Dog ialah subtaip bagi Animal.
let dogs: Dog[] = [];
let animals: Animal[] = dogs; // ✅ Dog[] is assignable to Animal[]
Jenis pulangan dan array bersifat covariant: jika Dog ⊆ Animal, maka Dog[] ⊆ Animal[]. Sebuah fungsi yang memulangkan Dog boleh digunakan di tempat yang menjangkakan satu yang memulangkan 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
Parameter fungsi bersifat contravariant: Handler<Animal> boleh ditetapkan kepada Handler<Dog>, sebaliknya daripada hubungan elemen. Ini adalah kukuh — sesuatu yang mengendalikan semua haiwan sudah tentu mengendalikan anjing.
// Method parameters in TS are bivariant by default (a known unsound convenience)
interface Comparer<T> { compare(a: T): void; }
TypeScript memeriksa jenis fungsi berdiri sendiri secara contravariant hanya di bawah strictFunctionTypes; parameter kaedah secara sengaja bersifat bivariant demi keergonomikan, yang secara teknikalnya tidak kukuh.
Variance menerangkan mengapa penetapan tertentu dibenarkan atau ditolak — mengapa Dog[] muat dalam Animal[] tetapi sebuah callback (d: Dog) => void tidak selalu boleh menggantikan (a: Animal) => void.
Memahaminya membantu anda mereka bentuk API generik (cth. kedudukan baca-sahaja lwn tulis) dan menyahkod ralat "not assignable" yang mengelirukan melibatkan fungsi dan generik.