Menu

Utility Types ב-TypeScript: הרשימה המלאה עם דוגמאות

כל ה-utility types המובנים של TypeScript במקום אחד: Partial, Required, Readonly, Pick, Omit, Record, Exclude, Extract, NonNullable, Parameters, ReturnType, Awaited, טיפוסי המחרוזות ועוד, כל אחד עם תיאור של שורה אחת ודוגמה להרצה.

בדף הזה יש עורכים שאפשר להריץ - לערוך, להריץ ולראות את הפלט מיד.

Utility types הם טיפוסים גנריים שמובנים ב-TypeScript והופכים טיפוס אחד לטיפוס אחר. במקום לכתוב טיפוס User שני שבו כל השדות אופציונליים, כותבים Partial<User>; במקום להעתיק שלושה שדות, Pick<User, "id" | "name">. הם גלובליים, כך שלא צריך לייבא אותם.

כש-User משתנה, כל ארבעת הטיפוסים הנגזרים משתנים איתו. הספרייה הסטנדרטית של TypeScript (lib.es5.d.ts) מצהירה על 22 utility types. הסעיפים הבאים מפרטים את כולם, מקובצים לפי סוג הטיפוס שהם עובדים עליו, עם קישור לעמוד המפורט כשיש כזה.

טיפוסי אובייקט: Partial, Required, Readonly, Pick, Omit, Record

Utility typeמה הוא עושהדוגמה
Partial<T>הופך כל property לאופציונליPartial<User> לנתונים של עדכון
Required<T>הופך כל property לחובה (מסיר את ?)Required<Config> אחרי שהוחלו ערכי ברירת המחדל
Readonly<T>הופך כל property ל-readonlyReadonly<State>
Pick<T, K>משאיר רק את המפתחות KPick<User, "id" | "name">
Omit<T, K>מסיר את המפתחות KOmit<User, "password">
Record<K, V>טיפוס אובייקט עם מפתחות K וערכים VRecord<"en" | "de", string>

Required<T> הוא ההפך של Partial<T>; עמוד ה-Partial מסביר את שניהם, כולל ה-undefined המפורש ש-spread כמו זה מעביר הלאה.

טיפוסי union: Exclude, Extract, NonNullable

Utility typeמה הוא עושהדוגמה
Exclude<U, M>מסיר את חברי ה-union שניתן להציב ב-MExclude<"a" | "b" | "c", "a"> הוא "b" | "c"
Extract<U, M>משאיר את חברי ה-union שניתן להציב ב-MExtract<string | number, number> הוא number
NonNullable<T>מסיר את null ואת undefinedNonNullable<string | null> הוא string

שלושת אלה עובדים על unions, לא על אובייקטים. זה ההבדל המרכזי בינם לבין Pick ו-Omit, שמקבלים טיפוס אובייקט ורשימה של המפתחות שלו.

טיפוסי פונקציות ומחלקות: Parameters, ReturnType ועוד

Utility typeמה הוא עושהדוגמה
ReturnType<F>טיפוס ההחזרה של טיפוס פונקציהReturnType<typeof createStore>
Parameters<F>טיפוסי הפרמטרים כ-tupleParameters<typeof fetchPage>[0]
ConstructorParameters<C>הפרמטרים של הבנאי של מחלקה כ-tupleConstructorParameters<typeof Point>
InstanceType<C>טיפוס המופע שבנאי יוצרInstanceType<typeof Point>
ThisParameterType<F>הטיפוס של פרמטר ה-this של פונקציהThisParameterType<typeof greet>
OmitThisParameter<F>טיפוס הפונקציה בלי פרמטר ה-this שלההטיפוס של greet.bind(obj)
ThisType<T>קובע את הטיפוס של this בתוך המתודות של object literalמשמש עם noImplicitThis ב-APIs בסגנון builder
NoInfer<T>מונע הסקה של פרמטר טיפוס מהמיקום הזהfallback: NoInfer<C>

צריך את typeof createOrder כי ה-utility types האלה מקבלים טיפוס, ו-createOrder הוא ערך. אותו דבר עם מחלקות: typeof Point הוא טיפוס הבנאי, ואילו Point לבד כטיפוס כבר מציין את טיפוס המופע.

NoInfer קובע מאיפה טיפוס גנרי מקבל את הטיפוס שלו:

בלי NoInfer, TypeScript היה מסיק את C משני הארגומנטים ומרחיב אותו ל-"red" | "green" | "blue", כך שטעות ההקלדה בערך ברירת המחדל הייתה מתקבלת.

טיפוסי מחרוזות: Uppercase, Lowercase, Capitalize, Uncapitalize

Utility typeמה הוא עושהדוגמה
Uppercase<S>ממיר טיפוס literal של מחרוזת לאותיות גדולותUppercase<"get"> הוא "GET"
Lowercase<S>ממיר אותו לאותיות קטנותLowercase<"GET"> הוא "get"
Capitalize<S>הופך את התו הראשון לאות גדולהCapitalize<"name"> הוא "Name"
Uncapitalize<S>הופך את התו הראשון לאות קטנהUncapitalize<"Name"> הוא "name"

ארבעת אלה מובנים בקומפיילר ולא כתובים ב-TypeScript, והם שימושיים במיוחד בתוך template literal types, למשל `on${Capitalize<E>}` לשמות של event handlers.

Promises: Awaited

Utility typeמה הוא עושהדוגמה
Awaited<T>הטיפוס שמקבלים מ-await, עם פריסה של promises מקונניםAwaited<Promise<Promise<number>>> הוא number

Awaited<ReturnType<typeof fn>> היא הדרך המקובלת לתת שם לטיפוס התוצאה של פונקציה async בלי להצהיר עליו בנפרד.

שילוב utility types

אפשר לקנן utility types זה בתוך זה. כמה שילובים חוזרים מספיק פעמים כדי שכדאי להכיר אותם בעל פה:

קוראים utility type מקונן מבפנים החוצה: Readonly<Pick<Post, "id" | "title">> קודם משאיר שני properties, ואחר כך הופך אותם לקריאה בלבד. מאותם חלקים בונים helper בשם PartialBy שהופך רק חלק מהמפתחות לאופציונליים; עמוד ה-Partial כותב אותו במלואו.

Utility types לא עושים כלום בזמן ריצה

כל utility type נמחק כשהקוד עובר קומפילציה. ערך מטיפוס Omit<User, "password"> עדיין יכול להכיל סיסמה בזמן ריצה, אם האובייקט שממנו הוא הגיע הכיל אחת:

הטיפוס רק מגביל את מה שהקוד שלכם רשאי לקרוא. כדי להסיר שדה מהנתונים, הוציאו אותו עם destructuring כמו בשורות האחרונות, וכדי למנוע שינויים בזמן ריצה השתמשו ב-Object.freeze, לא ב-Readonly. הטיפוסים המובנים הם mapped types ו-conditional types של שורה אחת, כך שבאותם כלים אפשר לכתוב גם utility types משלכם.

שאלות נפוצות

מה הם utility types ב-TypeScript?

טיפוסים גנריים שמגיעים עם TypeScript ומשנים טיפוסים אחרים: Partial<T> הופך כל property לאופציונלי, Pick<T, K> משאיר רק חלק מה-properties, ReturnType<F> מחזיר את טיפוס ההחזרה של פונקציה, וכן הלאה. הם מוצהרים בספרייה הסטנדרטית, כך שמשתמשים בהם בלי לייבא שום דבר.

האם צריך לייבא utility types?

לא. Partial, Omit, Record, ReturnType וכל השאר הם טיפוסים גלובליים מקובצי הספרייה המובנים של TypeScript. כתבו Partial<User> בכל מקום; לא צריך import ולא צריך חבילת npm.

אילו utility types מובנים ב-TypeScript?

22, כולם מוצהרים ב-lib.es5.d.ts: Partial, Required, Readonly, Pick, Omit, Record, Exclude, Extract, NonNullable, Parameters, ConstructorParameters, ReturnType, InstanceType, ThisParameterType, OmitThisParameter, ThisType, NoInfer, Awaited, Uppercase, Lowercase, Capitalize ו-Uncapitalize.

האם utility types משנים אובייקטים בזמן ריצה?

לא. הם רק מתארים טיפוסים ונמחקים מפלט ה-JavaScript. Omit<User, "password"> לא מוחק שום property בשם password, ו-Readonly<T> לא מקפיא שום דבר. כדי לשנות את האובייקט עצמו צריך לכתוב קוד: destructuring עם rest, Object.freeze וכדומה.

אפשר לכתוב utility types משלי?

כן. המובנים הם TypeScript רגיל: רובם mapped types או conditional types של שורה אחת ב-lib.es5.d.ts. type Nullable<T> = { [K in keyof T]: T[K] | null } הוא utility type מותאם אישית שנכתב באותה דרך.

איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל