تايبسكريبت - ما الفرق بين تنفيذين لنوع الأدوات Pick
أنا أجرب هذا: https://github.com/type-challenges/type-challenges/blob/master/questions/4-easy-pick/README.md
لا أستطيع فهم الفرق بينهم:
type MyPick<T, K> = T extends {} ? K extends keyof T ? {[P in K]: T[P]} : never : never
type MyPick<T extends {}, K extends keyof T> = {[P in K]: T[P]};
يمكنك لعبها على: أدخل وصف الرابط هنا
حالة اختبار:
type A = {name: string; value: number;}
type B = MyPick1<A, 'name' | 'value'> // got {name: string} | {value: number}
type C = MyPick2<A, 'name' | 'value'> // got {name: string; value: number;}
أنا مرتبك من النتائج، ولماذا؟
الإجابة رقم 1
أول MyPick:
type MyPick<T, K> = T extends {} ? K extends keyof T ? {[P in K]: T[P]} : never : never
يمكنه قبول أي نوعين عامين. أعني، يمكنك استدعاؤه باستخدام MyPick<1,2>/never أو MyPick<[], false>/never، وهو بالطبع لا معنى له ولكنه مسموح به لأن القيود يتم التحقق منها داخل جسم الأداة المساعدة.
الثاني MyPick:
type MyPick<T extends {}, K extends keyof T> = {[P in K]: T[P]};
هذا MyPick لديه قيود على كل من الوسيطين. يجب أن يمتد الوسيط الأول إلى {} والتي هي في الواقع نوع any، ويجب أن يكون الوسيط الثاني مفتاحًا للوسيط الأول.
على سبيل المثال:
type Test0 = MyPick1<2, 'toString'> // ok
type Test1 = MyPick1<2, 3> // expected error
كما قد تكون لاحظت، ما زلت مسموحًا لك بتمرير الوسيطة الأولى كنوع بدائي لأن كل قيمة في جافاسكريبت هي كائن، وبالتالي لها مفاتيحها الخاصة.
// "toString" | "toFixed" | "toExponential" | "toPrecision" | "valueOf" | "toLocaleString"
type NumberKeys = keyof number;
أفترض أنك تريد تطبيق قيد حيث يُسمح للمستخدم بتمرير كائن فقط كالحجة الأولى، وهذا يعني أنه يجب عليك استخدام قيد Record<PropertyKey, any>. على سبيل المثال:
type Test0 = MyPick1<{ age: number }, 'age'> // ok
type Test1 = MyPick1<2, 'toString'> // error
type Test2 = MyPick1<true, 3> // expected error
لماذا MyPick1 يُرجع نوع Union؟
انظر إلى هذا:
// Slightly reduced
type MyPick1<T, K> = K extends keyof T ? { [P in K]: T[P] } : never
type A = { name: string; value: number; }
type B = MyPick1<A, 'name' | 'value'> // got {name: string} | {value: number}
MyPick1 يُرجع اتحادًا بسبب التوزيعية. يرجى قراءة هذا القسم من الوثائق بدقة. هذه ميزة مهمة جدًا.
نوع الاتحاد K يتوزع، هذا يعني أن هذا السطر { [P in K]: T[P] } يُطبق على كل اتحاد.
انظر مثالًا آخر، لتوضيح الأمر أكثر:
type Distibutive<T> = T extends any ? T[] : never
type Result1 = Distibutive<'a' | 'b'> // "a"[] | "b"[]
// This is how you disable distributivity
type NonDistibutive<T> = [T] extends [any] ? T[] : never
type Result2 = NonDistibutive<'a' | 'b'> // ("a" | "b")[]
