في TypeScript، ماذا يعنيان "extends keyof" و "in keyof"؟
في TypeScript، يتم تعريف بعض الأنواع باستخدام extends keyof أو in keyof. لقد حاولت أن أفهم ما تعنيه، لكن حتى الآن لم أنجح.
ما فهمته هو أن keyof بمفرده يُرجع نوع اتحاد يحتوي على جميع الأسماء كقيم محتملة الموجودة كأسماء خصائص على النوع الذي تحدده بعد keyof.
type T = keyof string;
T لذلك يعادل startsWith | endsWith | trim | substring | ....
هل هذا صحيح؟
الآن، إذا حاولت التفكير فيما تعنيه extends keyof و in keyof، فإن إحساسي الغريزي يقول ما يلي:
extends keyofهو أي نوع مشتق منT، أي أنه يحتوي على جميع هذه القيم الممكنة، ولكن ربما أكثر.in keyofهو أي نوع يأخذ قيمًا منT، ولكن ليس بالضرورة كل القيم (قد يكون ممكنًا، لكنه أقل احتمالًا).
إذاً، من هذه الزاوية extends keyof ستصف علاقة >=، وin keyof ستصف علاقة <=. هل هذا صحيح؟ إذا لم يكن كذلك، ما هو الصحيح؟
الإجابة رقم 1
بالنسبة لأي نوع T، keyof T هو اتحاد أسماء الخصائص العامة والمعروفة لـ T.
مثال :
interface Person {
age: number;
name: string;
}
type PersonKeys = keyof Person; // "age" | "name"
افتراضك أن keyof string يعطي startsWith | endsWith | trim | ... هو صحيح إذن. يمكنك معرفة المزيد عن ذلك في ملاحظات إصدار نوع البحث.
يمتد مفتاح
يُستخدم extends، في هذه الحالة، لتقييد نوع معلمة عامة. مثال:
<T, K extends keyof T>K يمكن لذلك فقط أن يكون اسم خاصية عامة لـ T. لا علاقة له بتوسيع نوع أو الوراثة، على عكس توسيع الواجهات.
يمكن أن يكون استخدام extends keyof كالتالي:
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const person: Person = {
age: 22,
name: "Tobias",
};
// name is a property of person
// --> no error
const name = getProperty(person, "name");
// gender is not a property of person
// --> error
const gender = getProperty(person, "gender");
بعيدًا عن الوثائق المتعلقة بأنواع الفهارس، وجدت هذا المقال مفيدًا.
في مفتاح
in يُستخدم عندما نحدد توقيع فهرس نريد كتابته بنوع اتحاد من النصوص أو الأرقام أو رموز الحرف. بالمشاركة مع keyof يمكننا استخدامه لإنشاء ما يُسمى نوع مُعَدَّل، والذي يعيد رسم جميع خصائص النوع الأصلي.
يمكن أن يكون استخدام in keyof كالتالي:
type Optional<T> = {
[K in keyof T]?: T[K]
};
const person: Optional<Person> = {
name: "Tobias"
// notice how I do not have to specify an age,
// since age's type is now mapped from 'number' to 'number?'
// and therefore becomes optional
};
بعيدًا عن الوثائق حول الأنواع المُرَسَّمة، وجدت مرة أخرى هذه المقالة المفيدة.
معلومة ممتعة: النوع
Optional<T>الذي أنشأناه للتو له نفس توقيع النوع المساعد الرسميPartial<T>!
