ความแปรปรวน อธิบายว่าการสร้างประเภทย่อยของประเภทคอมโพสิตนั้นเกี่ยวข้องกับการสร้างประเภทย่อยของชิ้นส่วนอย่างไร — กล่าวคือ Container<Sub> สามารถกำหนดให้กับ Container<Super> เมื่อใด
ให้ Dog เป็นประเภทย่อยของ Animal
ความแปรปรวน อธิบายว่าการสร้างประเภทย่อยของประเภทคอมโพสิตนั้นเกี่ยวข้องกับการสร้างประเภทย่อยของชิ้นส่วนอย่างไร — กล่าวคือ Container<Sub> สามารถกำหนดให้กับ Container<Super> เมื่อใด
ให้ Dog เป็นประเภทย่อยของ Animal
let dogs: Dog[] = [];
let animals: Animal[] = dogs; // ✅ Dog[] is assignable to Animal[]
ประเภท return และ arrays เป็น ความแปรปรวนร่วม: ถ้า Dog ⊆ Animal แล้ว Dog[] ⊆ Animal[] ฟังก์ชันที่ส่งคืน Dog สามารถใช้ได้เมื่อคาดว่าจะมีการส่งคืน 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
พารามิเตอร์ ฟังก์ชันเป็นความแปรปรวนตรงกันข้าม: Handler<Animal> สามารถกำหนดให้กับ Handler<Dog> ซึ่งเป็น ตรงกันข้าม กับความสัมพันธ์ขององค์ประกอบ นี่คือวิธีที่ถูกต้อง — สิ่งที่จัดการสัตว์ทั้งหมดแน่นอนว่าจัดการสุนัขได้
// Method parameters in TS are bivariant by default (a known unsound convenience)
interface Comparer<T> { compare(a: T): void; }
TypeScript ตรวจสอบประเภทฟังก์ชันแบบสแตนด์อโลนเป็นตรงกันข้ามเฉพาะภายใต้ strictFunctionTypes เท่านั้น พารามิเตอร์เมธอดจะเป็น bivarian โดยจงใจเพื่อความสะดวก ซึ่งในทางเทคนิคจะไม่ถูกต้อง
ความแปรปรวนอธิบาย ทำไม การมอบหมายบางอย่างได้รับอนุญาตหรือถูกปฏิเสธ — ทำไม Dog[] จึงเหมาะสมกับ Animal[] แต่ callback (d: Dog) => void ไม่สามารถให้บริการสำหรับ (a: Animal) => void ได้เสมอไป
การทำความเข้าใจมันจะช่วยให้คุณออกแบบ API ทั่วไป (เช่น ตำแหน่งอ่านอย่างเดียว vs เขียน) และถอดรหัสข้อผิดพลาด "ไม่สามารถมอบหมาย" ที่สับสนเกี่ยวกับฟังก์ชันและเจเนริก