Menu

TypeScript template literal types: תחביר ודוגמאות

Template literal types בונים טיפוסי string literal באותו תחביר של גרשיים הפוכים כמו template strings ב-JavaScript: on${Capitalize<E>}. למדו את התחביר, איך unions מוכפלים, Uppercase ו-Capitalize, תבניות כמו ${number}px, getters עם mapped types ופירוק מחרוזות עם infer.

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

Template literal type בונה טיפוסי string literal באותו תחביר של גרשיים הפוכים כמו template string ב-JavaScript. `on${Capitalize<"click" | "focus">}` הוא הטיפוס "onClick" | "onFocus", שהקומפיילר מחשב:

Template literal types קיימים רק בזמן קומפילציה. הם בודקים string literals וערכים עם טיפוס בזמן כתיבת הקוד, ולא מוסיפים דבר לפלט ה-JavaScript. טבלת ה-handlers שלמעלה משתמשת ב-Record כדי לחייב פונקציה אחת לכל שם.

תחביר

בתוך הגרשיים ההפוכים כותבים טקסט ליטרלי ומצייני מקום ${...}. מציין מקום מחזיק טיפוס, לא ערך: טיפוס ליטרלי של string, number, bigint או boolean, union שלהם, או אחד הטיפוסים הרחבים string, number, bigint, boolean, null ו-undefined.

מציין מקום עם טיפוס רחב כמו string או number יוצר תבנית: הטיפוס נשאר `hello ${string}` וכל מחרוזת שמתאימה לו מתקבלת. מציין מקום עם union סופי, כמו boolean, מורחב לאיברים שלו.

Unions מוכפלים

עם כמה unions, התוצאה היא כל הצירופים:

שלושה גדלים כפול שני גוונים נותנים שישה איברים. המספר גדל מהר: חמישה מצייני מקום שכל אחד מהם מחזיק union של עשר אותיות יתנו 100,000 איברים, ו-TypeScript מסרב עם error TS2590: Expression produces a union type that is too complex to represent. השתמשו במציין מקום רחב כמו ${string} כשלא צריך כל ערך מדויק.

Uppercase, Lowercase, Capitalize, Uncapitalize

ארבעה טיפוסים מובנים משנים את האותיות הגדולות והקטנות בטיפוסי string literal. הם intrinsic: ממומשים בתוך הקומפיילר, ולא כתובים ב-TypeScript.

טיפוסקלטתוצאה
Uppercase<S>"hello world""HELLO WORLD"
Lowercase<S>"Content-Type""content-type"
Capitalize<S>"hello world""Hello world"
Uncapitalize<S>"UserName""userName"

הם משנים רק טיפוסים. כדי לבנות את המחרוזת המתאימה בזמן ריצה, עדיין קוראים ל-toUpperCase() או חותכים ומגדילים את האות הראשונה בעצמכם, ואומרים ל-TypeScript שלתוצאה יש את הטיפוס המדויק:

ה-as נחוץ כי toUpperCase() מוגדרת כמחזירה string רגיל. החתימה של הפונקציה היא מה שהקוראים לה רואים, ולכן ל-capitalize("report") יש את הטיפוס הליטרלי "Report".

תבניות מחרוזת: ${number}px ודומיו

טיפוס תבנית מקבל כל מחרוזת בצורה מסוימת. הוא שימושי לערכי CSS, למזהים ולמפתחות עם קידומת ידועה:

${number} מקבל כל מחרוזת ש-JavaScript קורא כמספר, וזה מתירני יותר ממה שנראה: "-3px", "1e3px" ו-"0x10px" כולם עוברים את בדיקת הטיפוסים. התייחסו לתבניות האלה כהגנה מפני שגיאות הקלדה בליטרלים, לא כבדיקת תקינות מלאה.

Template literals עם mapped types

Template literal types שימושיים במיוחד כפסוקית as של mapped type, שם הם יוצרים שמות מאפיינים משמות מאפיינים אחרים:

string & K משאיר רק מפתחות מסוג string, כי Capitalize לא מקבל מספרים או symbols. כל callback מקבל את טיפוס הפרמטר שלו מהמאפיין שהוא עוקב אחריו.

פירוק מחרוזות עם infer

ב-conditional type, template literal יכול להתאים למחרוזת ולתפוס חלקים ממנה עם infer. כך מחלצים את שמות הפרמטרים מתבנית של נתיב:

אם משמיטים את postId בקריאה, הקומפיילר מדווח שהוא חסר.

ביטויי תבנית מורחבים ל-string

ביטוי template string בקוד רגיל מקבל את הטיפוס string, גם כשכל החלקים שלו הם טיפוסים ליטרליים. הוסיפו as const כדי לשמור את ה-template literal type:

בלי as const, השמה של loose ל-`log:${Level}` נכשלת, כי string יכול להיות כל דבר.

שאלות נפוצות

מה הם template literal types ב-TypeScript?

טיפוסי string literal שנכתבים עם גרשיים הפוכים ומצייני מקום ${...}, כמו template strings ב-JavaScript אבל ברמת הטיפוסים. type Greeting = `hello ${string}` מקבל כל מחרוזת שמתחילה ב-hello , ו-`on${Capitalize<"click">}` הוא הטיפוס הליטרלי "onClick".

מה קורה כששמים union בתוך template literal type?

התבנית מורחבת לכל אחד מהאיברים, ועם כמה unions מקבלים את כל הצירופים. `${"sm" | "lg"}-${"red" | "blue"}` הוא "sm-red" | "sm-blue" | "lg-red" | "lg-blue". צירופים גדולים מאוד נכשלים עם השגיאה TS2590.

מה עושים Uppercase, Lowercase, Capitalize ו-Uncapitalize?

אלה טיפוסים מובנים שממירים טיפוסי string literal: Uppercase<"id"> הוא "ID", Lowercase<"ID"> הוא "id", Capitalize<"name"> הוא "Name" ו-Uncapitalize<"Name"> הוא "name". הם משנים רק טיפוסים; כדי לשנות מחרוזת בזמן ריצה עדיין קוראים ל-toUpperCase() ולמתודות דומות.

האם template literal types בודקים מחרוזות בזמן ריצה?

לא. כמו כל טיפוס של TypeScript הם נמחקים, ולכן הם בודקים רק string literals וערכים עם טיפוס בזמן קומפילציה. מחרוזת שמגיעה בזמן ריצה, מ-JSON או מקלט של משתמש, היא פשוט string עד שבודקים אותה בקוד שלכם.

למה ה-template string שלי מקבל את הטיפוס string ולא טיפוס ליטרלי?

ביטוי תבנית כמו `on${event}` מורחב ל-string כשמשימים אותו למשתנה. הוסיפו as const (`on${event}` as const) או הצהירו על טיפוס היעד, ו-TypeScript ישמור את ה-template literal type, למשל "onclick" | "onfocus".

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

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

להתחיל