تبدیلی بیان کرتی ہے کہ کسی مرکب قسم کی ذیلی اقسام اس کے اجزاء کی ذیلی اقسام سے کیسے متعلق ہیں — یعنی Container<Sub> کب Container<Super> کو تفویض کیا جا سکتا ہے؟
Dog کو Animal کی ذیلی قسم مانتے ہیں۔
let dogs: Dog[] = [];
let animals: Animal[] = dogs; // ✅ Dog[] is assignable to Animal[]
واپسی کی اقسام اور صفیں ہم آہنگ ہیں: اگر 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[] میں فٹ ہوتا ہے لیکن (d: Dog) => void کال بیک ہمیشہ (a: Animal) => void کی جگہ نہیں لے سکتا۔
اسے سمجھنا آپ کو عام API ڈیزائن کرنے (مثال کے طور پر صرف پڑھنے کے مقابلہ میں لکھنے کی پوزیشنیں) اور فنکشنز اور عام نوعیت کے شامل الجھن والی "تفویض نہ کی جا سکنے والی" خرابیوں کو سمجھنے میں مدد کرتا ہے۔