Διακύμανση περιγράφει πώς η υποτύπωση ενός σύνθετου τύπου σχετίζεται με την υποτύπωση των μερών του — δηλ. πότε το Container<Sub> μπορεί να αναθεθεί στο Container<Super>;
Έστω Dog υποτύπος του Animal.
let dogs: Dog[] = [];
let animals: Animal[] = dogs; // ✅ Dog[] is assignable to Animal[]
Οι τύποι επιστροφής και τα 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; οι παράμετροι μεθόδων είναι σκόπιμα διδιακύμαντες για λόγους εργονομίας, που είναι τεχνικά ανασφαλές.
Η διακύμανση εξηγεί γιατί ορισμένες αναθέσεις επιτρέπονται ή απορρίπτονται — γιατί το Dog[] ταιριάζει με το Animal[] αλλά ένα callback (d: Dog) => void δεν μπορεί πάντα να θέσει στη θέση ενός (a: Animal) => void.