Kodokon kodokon.com

التحميلات الزائدة، وthis المُصنَّف، والتغايرية

افهم حلّ التحميلات الزائدة، والبارامتر الزائف this، وقواعد التغايرية التي تحكم قابلية إسناد الدوال.

10 دقيقة · 3 أسئلة

افتح هذا الدرس في Kodokon

الدالّة ذات التحميل الزائد تكشف قائمة من التواقيع العامّة يتبعها توقيع تنفيذ واحد. نقطة أساسية في المواصفات: هذا الأخير غير مرئي من الخارج؛ فلا يمكن استدعاء سوى التحميلات المُصرَّح بها. يمرّ الحلّ على التواقيع من الأعلى إلى الأسفل ويحتفظ بأول توقيع متوافق: ضَع دائماً التوقيع الأكثر تخصيصاً أولاً، وإلا فلن يُختار أبداً.

TYPESCRIPT
function parse(input: string): number;
function parse(input: string[]): number[];
function parse(input: string | string[]) {
  return Array.isArray(input)
    ? input.map((s) => s.length)
    : input.length;
}

const single = parse("abc");      // number
const many = parse(["a", "bb"]);  // number[]
كل استدعاء يُحلَّل إلى تحميل زائد دقيق.

يُتيح لك TypeScript التصريح ببارامتر زائف this في الموضع الأول. وهو مَحذوف بالكامل من الجافاسكريبت المُنتَجة: إنه قيد ساكن محض على سياق الاستدعاء، يُفحَص عند تفعيل noImplicitThis. وتُتيح الأداتان ThisParameterType وOmitThisParameter استخراجه أو إزالته، وهذا جوهري لتصنيف الدوال المُعدّة للاستخدام مع call أو apply أو bind.

TYPESCRIPT
function greet(this: { name: string }, msg: string) {
  return `${msg}, ${this.name}`;
}

type Ctx = ThisParameterType<typeof greet>;
// { name: string }
type Fn = OmitThisParameter<typeof greet>;
// (msg: string) => string

const user = { name: "Ada", greet };
user.greet("Hello"); // "Hello, Ada"

// greet("Hi"); // error: missing this context
البارامتر this يقيّد موضع الاستدعاء، لا الجافاسكريبت المُنتَجة.

تصف التغايرية كيف تنتشر قابلية الإسناد عبر باني نوع. بالنسبة إلى الدوال، تكون أنواع الإرجاع تغايرية مشتركة (covariant)، ومع strictFunctionTypes تكون البارامترات تغايرية معاكسة (contravariant): يمكن لدالّة تقبل نوعاً أوسع أن تحلّ محلّ دالّة تقبل نوعاً أضيق، لا العكس أبداً. استثناء مقصود واحد: تبقى بارامترات التوابع المُصرَّح بها بالصيغة المختصرة ثنائية التغاير (bivariant)، وهو تسوية تاريخية، لولاها لما كان Array<Dog> قابلاً للإسناد إلى Array<Animal>. ومنذ الإصدار 4.7، يمكنك التأشير على التغايرية المتوقَّعة بواسطة in وout، مثل interface Producer<out T>، ويتحقّق المُصرِّف منها.

TYPESCRIPT
interface Animal { name: string }
interface Dog extends Animal { bark(): void }

declare let f: (a: Dog) => void;
declare let g: (a: Animal) => void;

f = g; // OK: g accepts a wider type, that is safe
// g = f; // error with strictFunctionTypes

interface Sink { accept(a: Animal): void }
interface DogSink { accept(a: Dog): void }
declare let s: Sink;
declare let d: DogSink;

d = s; s = d; // both compile: bivariance!
خصائص دوال صارمة، توابع ثنائية التغاير.

اختبار المعرفة

تأكّد من أنك تذكّرت النقاط الأساسية في هذا الدرس.

  1. عند استدعاء دالّة ذات تحميل زائد، أي توقيع يختار المُصرِّف؟
    • التوقيع الأكثر عموماً
    • أول توقيع متوافق حسب ترتيب التصريح
    • توقيع التنفيذ
    • اتّحاد كل التواقيع
  2. ماذا يحدث لبارامتر this الخاص بدالّة في الجافاسكريبت المُنتَجة؟
    • يصبح وسيطاً أول حقيقياً
    • يختفي: إنه تأشير ساكن محض
    • يُستبدَل باستدعاء لـbind
    • يُسبِّب خطأ وقت التشغيل إذا غاب
  3. مع strictFunctionTypes، أي صيغة تستفيد من الفحص التغايري المعاكس الصارم للبارامترات؟
    • التوابع بالصيغة المختصرة، مثل m(a: X): void
    • الخصائص من نوع دالّة، مثل m: (a: X) => void
    • الصيغتان معاً
    • لا هذه ولا تلك