Pick<T, K> הוא utility type מובנה שיוצר טיפוס אובייקט עם המאפיינים של T שנקובים ב-K בלבד. השתמשו בו כשפונקציה או קומפוננטה צריכות כמה שדות מטיפוס גדול יותר:
renderPreview מקבלת User מלא וגם אובייקט פשוט { id, name }, כי היא מבקשת רק את מה שהיא משתמשת בו. כך קל יותר לקרוא לה ולבדוק אותה. Pick קיים רק ברמת הטיפוסים: לאובייקט ada המלא עדיין יש את כל חמשת המאפיינים בזמן ריצה.
תחביר ובדיקת מפתחות
Pick<Type, Keys>
Keys הוא מפתח יחיד או איחוד של מפתחות, וכל אחד מהם חייב להיות קיים ב-Type. ההגדרה בספרייה הסטנדרטית של TypeScript הופכת את זה להגבלה:
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
בגלל K extends keyof T, מפתח עם שגיאת כתיב או מפתח חסר הוא שגיאת קומפילציה, והעורך יכול להשלים אוטומטית את שמות המפתחות:
השגיאה היא error TS2344: Type '"cost"' does not satisfy the constraint 'keyof Product'. זה הבדל לעומת Omit, שהמפתחות שלו לא נבדקים.
Pick שומר על readonly ועל אופציונליות
Pick ממפה על מפתחות של T, ולכן כל מאפיין שנבחר שומר על המגדירים שלו:
השורה האחרונה מציגה { id: 8 } כי readonly הוא בדיקה בזמן קומפילציה בלבד: ההשמה דווחה, הושתקה עם @ts-expect-error, ובכל זאת רצה. כדי לשנות את המגדירים תוך כדי בחירה, עטפו את התוצאה: Partial<Pick<Account, "plan">> או Required<Pick<Account, "email">>.
Pick מול Omit
Pick מציין מה להשאיר; Omit מציין מה להוריד. היום שניהם נותנים אותה תוצאה, אבל הם מתנהגים אחרת כשטיפוס המקור גדל:
Pick<T, K> | Omit<T, K> | |
|---|---|---|
| מה מפרטים | המפתחות שנשארים | המפתחות שמוסרים |
מאפיינים חדשים ב-T | לא נכללים | נכללים אוטומטית |
מפתח לא מוכר ב-K | שגיאת קומפילציה (TS2344) | מתקבל בשקט |
| מתאים ל | תגובות API, תצוגות ציבוריות, props | "הכול חוץ מהסוד" |
לנתונים שיוצאים מהשרת שלכם, Pick היא ברירת המחדל הבטוחה יותר: שום דבר לא מופיע בטיפוס אלא אם מישהו הוסיף אותו בכוונה.
בחירה מטיפוסים מקוננים
Pick רואה רק מפתחות ברמה העליונה: נתיב עם נקודות כמו Pick<Customer, "address.city"> הוא שגיאה (TS2344), ולא בחירה מקוננת. השתמשו ב-indexed access type כדי להגיע לטיפוס המקונן, ואז בחרו ממנו:
Customer["address"] הוא הטיפוס של המאפיין address. אותו תחביר מגיע גם לאיברי מערך: עבור מאפיין orders: Order[], Customer["orders"][number] הוא Order.
פונקציית pick() עם טיפוסים
Pick לא עושה כלום בזמן ריצה. פונקציה גנרית קטנה מעתיקה את המאפיינים שנבחרו לאובייקט חדש ומחזירה בדיוק Pick<T, K>:
K extends keyof T מאפשר ל-TypeScript להסיק את K מארגומנטי המחרוזת, כך שלטיפוס ההחזרה יש בדיוק את המפתחות שנבחרו. ה-assertion {} as Pick<T, K> נחוץ כי לאובייקט ריק עדיין אין את המאפיינים האלה; הלולאה ממלאת אותם.
בחירת מאפיינים לפי טיפוס הערך
Pick בוחר לפי שם המפתח. כדי לבחור לפי טיפוס המאפיין, למשל "כל שדות המחרוזת", כתבו mapped type עם סינון מפתחות:
פסוקית ה-as ממפה כל מפתח לעצמו כשהטיפוס שלו מתאים ול-never אחרת, ומפתחות never מושמטים. דקות אחת: הטיפוס של מאפיין אופציונלי כולל undefined, ולכן subtitle?: string אופציונלי לא ייחשב כאן string; בדקו מול string | undefined כדי לכלול אותו.
שאלות נפוצות
מה Pick עושה ב-TypeScript?
Pick<T, K> בונה טיפוס אובייקט שמכיל רק את המאפיינים של T שהמפתחות שלהם נמצאים ב-K. Pick<User, "id" | "name"> הוא { id: number; name: string } כשל-User יש את שני המאפיינים האלה ועוד אחרים. הוא עובד על טיפוסים בלבד ולא מסיר שום דבר מאובייקטים בזמן ריצה.
מה ההבדל בין Pick ל-Omit?
Pick מפרט את המאפיינים שנשארים, Omit מפרט את אלה שמוסרים. כשטיפוס המקור מקבל מאפיין חדש, Omit כולל אותו אוטומטית ו-Pick לא. Pick גם בודק שהמפתחות שלו קיימים בטיפוס; Omit מקבל כל מפתח.
איך בוחרים כמה מאפיינים ב-TypeScript?
מעבירים איחוד של מפתחות: Pick<User, "id" | "name" | "email">. כל המפתחות חייבים להיות קיימים ב-User, אחרת הקומפיילר מדווח על שגיאה TS2344.
איך בוחרים מאפיין מקונן ב-TypeScript?
Pick בוחר רק מאפיינים ברמה העליונה. הגיעו לטיפוס המקונן עם indexed access type ובחרו ממנו: Pick<User["address"], "city">. כדי לשמור על הקינון, שלבו ביניהם: Pick<User, "id"> & { address: Pick<User["address"], "city"> }.
האם Pick שומר על המגדירים readonly ואופציונלי?
כן. Pick הוא mapped type על מפתחות של T, ולכן מאפיין שהוא readonly או אופציונלי ב-T נשאר כזה גם בטיפוס שנבחר.