範本文字類型建立在 字串文字類型 上,並具有透過聯集擴充為多個字串的能力。
它們與 JavaScript 中的範本文字字串 具有相同的語法,但用於類型位置。與具體文字類型一起使用時,範本文字會透過串接內容產生新的字串文字類型。
tsTry
typeWorld = "world";typeGreeting = `hello ${World }`;
當聯集用於內插位置時,類型是每個聯集成員可以表示的每個可能的字串文字的集合
tsTry
typeEmailLocaleIDs = "welcome_email" | "email_heading";typeFooterLocaleIDs = "footer_title" | "footer_sendoff";typeAllLocaleIDs = `${EmailLocaleIDs |FooterLocaleIDs }_id`;
對於範本文字中的每個內插位置,聯集會交叉相乘
tsTry
typeAllLocaleIDs = `${EmailLocaleIDs |FooterLocaleIDs }_id`;typeLang = "en" | "ja" | "pt";typeLocaleMessageIDs = `${Lang }_${AllLocaleIDs }`;
我們通常建議人們對大型字串聯集使用即時產生,但這在較小的案例中很有用。
類型中的字串聯合
在範本字串中定義基於類型內部資訊的新字串時,其功能才會發揮作用。
考慮一個函式 (makeWatchedObject
) 將一個名為 on()
的新函式新增到傳遞的物件。在 JavaScript 中,其呼叫可能如下所示:makeWatchedObject(baseObject)
。我們可以將基礎物件想像成如下所示
tsTry
constpassedObject = {firstName : "Saoirse",lastName : "Ronan",age : 26,};
將新增到基礎物件的 on
函式預期兩個引數,一個 eventName
(一個 字串
) 和一個 callback
(一個 函式
)。
eventName
應為 attributeInThePassedObject + "Changed"
形式;因此,firstNameChanged
來自基礎物件中的屬性 firstName
。
callback
函式在呼叫時
- 應傳遞與名稱
attributeInThePassedObject
相關聯的類型的值;因此,由於firstName
被設定為字串
,因此firstNameChanged
事件的 callback 預期在呼叫時傳遞一個字串
。類似地,與age
相關聯的事件應預期以數字
引數呼叫 - 應具有
void
回傳類型 (為簡化示範)
on()
的天真函式特徵碼可能是:on(eventName: string, callback: (newValue: any) => void)
。然而,在前述說明中,我們識別了我們想要在程式碼中記錄的重要類型約束。範本字串類型讓我們將這些約束帶入我們的程式碼中。
tsTry
constperson =makeWatchedObject ({firstName : "Saoirse",lastName : "Ronan",age : 26,});// makeWatchedObject has added `on` to the anonymous Objectperson .on ("firstNameChanged", (newValue ) => {console .log (`firstName was changed to ${newValue }!`);});
請注意,on
會監聽事件 "firstNameChanged"
,而不仅仅是 "firstName"
。如果我們確保符合資格的事件名稱集合受到監控物件中屬性名稱的聯集的約束,並在最後加上「Changed」,那麼我們對 on()
的天真規格可能會變得更強大。雖然我們很樂意在 JavaScript 中進行此類計算,即 Object.keys(passedObject).map(x => `${x}Changed`)
,但類型系統中的模板字面值提供了類似的方法來進行字串處理
tsTry
typePropEventSource <Type > = {on (eventName : `${string & keyofType }Changed`,callback : (newValue : any) => void): void;};/// Create a "watched object" with an `on` method/// so that you can watch for changes to properties.declare functionmakeWatchedObject <Type >(obj :Type ):Type &PropEventSource <Type >;
有了這個,我們可以建立一個在給予錯誤屬性時會出錯的東西
tsTry
constperson =makeWatchedObject ({firstName : "Saoirse",lastName : "Ronan",age : 26});person .on ("firstNameChanged", () => {});// Prevent easy human error (using the key instead of the event name)Argument of type '"firstName"' is not assignable to parameter of type '"firstNameChanged" | "lastNameChanged" | "ageChanged"'.2345Argument of type '"firstName"' is not assignable to parameter of type '"firstNameChanged" | "lastNameChanged" | "ageChanged"'.person .on ("firstName" , () => {});// It's typo-resistantArgument of type '"frstNameChanged"' is not assignable to parameter of type '"firstNameChanged" | "lastNameChanged" | "ageChanged"'.2345Argument of type '"frstNameChanged"' is not assignable to parameter of type '"firstNameChanged" | "lastNameChanged" | "ageChanged"'.person .on ("frstNameChanged" , () => {});
使用模板字面值進行推論
請注意,我們並未從原始傳遞物件中提供的全部資訊中受益。給定 firstName
的變更(即 firstNameChanged
事件),我們應期望回呼會收到類型為 string
的引數。類似地,age
變更的回呼應收到 number
引數。我們天真地使用 any
來指定 callback
的引數類型。同樣地,模板字面值類型可以確保屬性的資料類型將與該屬性的回呼的第一個引數類型相同。
讓這成為可能的關鍵見解是:我們可以使用具有一般性的函式,例如
- 第一個引數中使用的字面值會擷取為字面值類型
- 該文字類型可以驗證為通用屬性中有效屬性的聯集
- 已驗證屬性的類型可以使用索引存取在通用結構中查詢
- 然後可以套用此打字資訊,以確保呼叫回函函式的引數是相同類型
tsTry
typePropEventSource <Type > = {on <Key extends string & keyofType >(eventName : `${Key }Changed`,callback : (newValue :Type [Key ]) => void): void;};declare functionmakeWatchedObject <Type >(obj :Type ):Type &PropEventSource <Type >;constperson =makeWatchedObject ({firstName : "Saoirse",lastName : "Ronan",age : 26});person .on ("firstNameChanged",newName => {console .log (`new name is ${newName .toUpperCase ()}`);});person .on ("ageChanged",newAge => {if (newAge < 0) {console .warn ("warning! negative age");}})
我們在此將 on
設為通用方法。
當使用者呼叫字串 "firstNameChanged"
時,TypeScript 會嘗試推論 Key
的正確類型。為此,它會將 Key
與 "Changed"
之前的內容比對,並推論字串 "firstName"
。一旦 TypeScript 找出這個字串,on
方法就可以在原始物件上擷取 firstName
的類型,在本例中為 string
。類似地,當呼叫 "ageChanged"
時,TypeScript 會找出屬性 age
的類型,為 number
。
可以結合不同的方式來進行推論,通常用於解構字串,並以不同的方式重建它們。
內在字串處理類型
為了協助字串處理,TypeScript 包含一組可於字串處理中使用的類型。這些類型內建於編譯器中以提升效能,且無法在 TypeScript 中包含的 .d.ts
檔案中找到。
Uppercase<StringType>
將字串中的每個字元轉換為大寫版本。
範例
tsTry
typeGreeting = "Hello, world"typeShoutyGreeting =Uppercase <Greeting >typeASCIICacheKey <Str extends string> = `ID-${Uppercase <Str >}`typeMainID =ASCIICacheKey <"my_app">
Lowercase<StringType>
將字串中的每個字元轉換為小寫等效字元。
範例
tsTry
typeGreeting = "Hello, world"typeQuietGreeting =Lowercase <Greeting >typeASCIICacheKey <Str extends string> = `id-${Lowercase <Str >}`typeMainID =ASCIICacheKey <"MY_APP">
Capitalize<StringType>
將字串中的第一個字元轉換成大寫等效字元。
範例
tsTry
typeLowercaseGreeting = "hello, world";typeGreeting =Capitalize <LowercaseGreeting >;
Uncapitalize<StringType>
將字串中的第一個字元轉換成小寫等效字元。
範例
tsTry
typeUppercaseGreeting = "HELLO WORLD";typeUncomfortableGreeting =Uncapitalize <UppercaseGreeting >;
內部字串處理類型技術詳細資料
截至 TypeScript 4.1,這些內部函式的程式碼直接使用 JavaScript 字串執行時間函式進行處理,且不具備地區設定感知能力。
function applyStringMapping(symbol: Symbol, str: string) {
switch (intrinsicTypeKinds.get(symbol.escapedName as string)) {
case IntrinsicTypeKind.Uppercase: return str.toUpperCase();
case IntrinsicTypeKind.Lowercase: return str.toLowerCase();
case IntrinsicTypeKind.Capitalize: return str.charAt(0).toUpperCase() + str.slice(1);
case IntrinsicTypeKind.Uncapitalize: return str.charAt(0).toLowerCase() + str.slice(1);
}
return str;
}