模板字面类型

模板字面类型建立在 字符串字面类型 之上,并且能够通过联合扩展成许多字符串。

它们具有与 JavaScript 中的模板字面字符串 相同的语法,但用于类型位置。当与具体字面类型一起使用时,模板字面通过连接内容来生成新的字符串字面类型。

type World = "world";

type Greeting = `hello ${World}`;

当在插值位置使用联合时,类型是可以由每个联合成员表示的每个可能的字符串字面的集合:

type EmailLocaleIDs = "welcome_email" | "email_heading";
type FooterLocaleIDs = "footer_title" | "footer_sendoff";

type AllLocaleIDs = `${EmailLocaleIDs | FooterLocaleIDs}_id`;

对于模板字面中的每个插值位置,联合是交叉相乘的:

type EmailLocaleIDs = "welcome_email" | "email_heading";
type FooterLocaleIDs = "footer_title" | "footer_sendoff";
type AllLocaleIDs = `${EmailLocaleIDs | FooterLocaleIDs}_id`;
type Lang = "en" | "ja" | "pt";

type LocaleMessageIDs = `${Lang}_${AllLocaleIDs}`;

我们通常建议人们对大型字符串联合使用提前生成,但这在较小的情况下很有用。

类型中的字符串联合

iypYkI3xyzvfxCi3esHAwIs/s61+Amb4qklGX4+1kAE8acHF9ykSUg6N3Fp8GAAu9AQlfUz/TuNS6hSSIlpjh+d8Xd6oOoJAdk2r5gdjgsxiQpjiTqiJlsFSF1cXbc+A

/qE9Bm8Po08cTmF2j81eIE+XGgF8kee/LER8PZfIIyYx+jwgosg7CiqDTi3IhY3M3Xohr4Y1oDOW+FB0PL91JZmBa967OM3hXzbDrB8hXYiZOz7+sGeCjOraK3Yp/101fE3AYkaEMgU0UCibIQe38KvUhwZ/ikbGao0tw60WwjVD2gF41sJe/+rTSibVqofsdUtmoCYsjRUkVsKgBurDJs3pmcq3mNa4NYRVtBl6C5de8GLGQI7oB8lXor/8AOMPXd0tjaR142JAWPdVbIKhFyuPHYFMQOWfcasoOjk5OyyZ6TfInoct4ektkyhyt79v0RLHcsTAUlPexcmCW4h/2KvCrq/BZswfFmXrW2Uh2b15g6hOpPzDewOSQkZNp2gd

const passedObject = {
  firstName: "Saoirse",
  lastName: "Ronan",
  age: 26,
};

4vgi0jxaVx0Zc5a+n3KtwDWfdqHIJdAJEByxHT23FEcPB0M+5W/G4xvMKEEmCkhVtMWQOEyS6v0TkXS1wwRMN6DShIM62eILTMdRz9JqHRxtP6wQMCBrUi+BQU5R/F0HfW72B+prR8hZ+h4fSIekkgmo2n51OM11+egMIENkamcOLM4SHHe+e5FHcIAYUGhH/CC+GRj6J92E2EahZVlOVx5b0sz+POqZeyv2YvB7Xr0lcs4ink7Xc5g4szntVWTCDiVY/oWKKMwINAYLoAvIDg==

SyHDmVXtrvr5jAxfVhYGPgpJ7aeOwITzvu+BlKyD/6OPvIq5gyhClU2DoN/3qE2PPAcNQ+ieudJ+VXvbXITvdz+hQFfjDaJKSzC25o3hoVCGvjON6sMMkxBf/JymXgp4EPqOZDuaVwhOdCz5p89re/prQTH7Bx1esCr3h0I4D1DMbthLWcjarjtb8SaT/YrhwA7275pvh9gvQW9S3SgEXLzghasspx4M0hO3zIVkeRgXH9SDZXd85R6cNyJ3rpyI

L2SaEon3UAUqvSDDydFnjOyfmkOUga/3+fzxwa2R1r0Sg8/RLDLLp5onwn6mWpUy

    QLsIL4vlCOOd6J2RTLBJhpRXBbCXUrlbDWC4uWrB4bDJh8XYi5PBJife4cmW+Ux1GJqbhpn1GQUO5edtO0Wmzp4b5IGQxyXzBuKET344tepjiBW7+23QRHKtb0y68dIiDyHWfcsecp/nGVC3lhCFQ4qKDIkgOJqpiFoRsBC+NJf+G4yeGVcz6YcFgfsdYiEcgdFIsp0cqfFfj9T/TygG27DIP9JRwLtYU6DLwtYvzmEr7nQgNfecXwEZ646l3qcagtt7v3Oenx+MPltfZTegMwRevK12lWHCoS2jUO/boe87PpVPI8MLEKgc57RtOFpI0WwZHyR8utiuBp92fPVi+y5AFWtbuQuonM+3dfyB8wP2za1FmrTOdChWAwzdnKODbqhWgwuEDBMYji8NeFPAyGkolHhFgTZAwKcCma0sth1bvyGT78fWkFytQ2gkAHtUFXgBlRBLHd7iCQVDh+rxn60ZXwg4bFoD3c5/oxBVler3wMfBZdp4hhNBu6J4NFjqJUGBBcyKwSQWcCny0s53ObQu9vFn3ZQ+mAtQu4ohp1V8roAso/5ktUn1fSyMD1S1b3jnoiFl7FfpGMJaZXpHcvvvA2Q4HNAAih0q/vUkodc=

NvmkkGEd0UFPldK6W5Ukh97dqTYjGZQ9oDY6Pndd3dHQ0cr+j/lBSgHCpsIIoCf6av7BM3MpJJZWxKNKGbdsE8rD6EhMLY2TgMTWWpSbT4xYRJVluEGR7uTP+CU3kh2Z/R+eDtFt4s8l+IvDgQcE982x7VRxNhGPhTubgyISac/E7on02n16b78N7TI4PMNzeLqVITL2++LjjAvZsku6GvJxuBh84cnE9/N5WalDYH6PH6BfUUARxxzsISW5SFMuuc1fuUF+5aNgooqyjZgu73QXKB8nJhf38f6EJ7LMcsHH/UunIMNRJ/HY6ARfaq3RXu/3Z9k+vL6iyQcK9SxmOWx9ZbjbgiarY/krsRviZfX3eEV4sRp94aUpt7wRVWNstIePavlahRmX0KFPX2c+bQ==

declare function makeWatchedObject(obj: any): any;
const person = makeWatchedObject({
  firstName: "Saoirse",
  lastName: "Ronan",
  age: 26,
});

// makeWatchedObject has added `on` to the anonymous Object

person.on("firstNameChanged", (newValue) => {
  console.log(`firstName was changed to ${newValue}!`);
});

/rivtr76VE2FY4YTJFpLaa8OngH5SW9C4u9lISiMQgpyvtC4HvnzaBKyTSiqtLJgUwNWMiXFWhuxYH6nSa/ivRdO/3xVInsa+4NbFTYZXdvbjNBt2FqWTDFz6HCweGhtG2oo+/efR1G4JsVTINXoINo5eBBNEbZmEWrun1NBYIlsjHEdZC/srSAEbyo789JAc9PMaSGDNMjcDR5U4Gp+iMW+h0lsjPCVT2f2L1KKaESVtJXS5zmbHjXvNcbJFM6sWM184Bw1MgYTQeAxb0SY4NFTQU1SPpC98cIxSbf7ict0noymoanmtEaIfrj4CaRg7kqtRnzS1UVl7hqUndvl+ZtD7S6FYyhwWoQEu4P28koCl9K2Y7qIF1CdXNBaeHxeZ7CxVWLAszXz7GJhQBjFZKG49GZ/s3Hr+gyXMitlgmB7ygCfR1qj8aTUUgg8keSql1xEMY4d5LdpeYW3xzwAzKej6LJ2FfCgp80uNtvGJXjo2zenK2TXSPC502GsKe00Z5bOd2TGbeWOUIphOlbT17CLb2WXtHWcMX5z2BiKQu3uFPnl1J90E6iTA5H68jDAdAVrORVlY0W1IwFgQ8GbXcXMZMhZYhJCtHqrAFUb2dUu1H4gVTixhygtQPoy+FJlVEEaqMk8q5qjctPhHoHJqO6LrrQFOgvlH5VssmYv56CewpAgoDTehV0+SfpJ5t2m50Txr/BWBxiK8jQaUjqj8g==

type PropEventSource<Type> = {
    on(eventName: `${string & keyof Type}Changed`, callback: (newValue: any) => void): void;
};

/// Create a "watched object" with an 'on' method
/// so that you can watch for changes to properties.
declare function makeWatchedObject<Type>(obj: Type): Type & PropEventSource<Type>;

bdlziiF4qLVTvsar4umwxOWSstJoM5NHQUGzDQXFGkyej/ar/7S1VxHtI0J/4s5hPBrX/45h7MGx7S9315y/i7OpOY6azrsdmhomkV3jPl5/eiLrsucB7JwW9BCzjmuc

type PropEventSource<Type> = {
    on(eventName: `${string & keyof Type}Changed`, callback: (newValue: any) => void): void;
};

declare function makeWatchedObject<T>(obj: T): T & PropEventSource<T>;
const person = makeWatchedObject({
  firstName: "Saoirse",
  lastName: "Ronan",
  age: 26
});

person.on("firstNameChanged", () => {});

// Prevent easy human error (using the key instead of the event name)
person.on("firstName", () => {});

// It's typo-resistant
person.on("frstNameChanged", () => {});

使用模板字面进行推理

O+5dnzQBRrHg7IA7FL4uXLCdAlL7xtT6GeFlU/pJoqUzF8NPhEpjhd3yZ0272fLNfYSQ+VMzLg1Fy1Lu3rXowaCtWLXK+jg0xDmSo5VJL97r8sVk2H1x1bFixEWEvhXimOnIDQ7s5eHjtgEAH83VIEf33otTosKua+zPdXuZHfuTG5quBq0SRGdI0EcCEYIOOnwu2q5jVqA+5zh2fwEINjZn5DjUKbylOJJyHrxr5EJ26waPMBWHanhKr2DuV61JL0/Q1mzN+KZicoI15G5Ipdhm1xKOgABZhMUeeX6jFWTzjy0XoZRWmT2SnCUmySuuCWM5ZwioeEnsV2DRfo2DB2doekgzhNqQC4ozecoL8A5Wn5q9Nqfl8vMX1luD6+X+E7aHmFN4hSFJwpA49YCOBYTSx3zR6tCVXaZMNz+/uhC36Ax0uFRnwXeOHpJ5FOWRyJoLG49igVp3rItZQsVGZV/3oMQhvGZxcIm53R+OkemzJLQsCLou8ZAUTFULenEIOYf88k4iAFaN7354df0ZE0Wy8l1MfuA6y7RdlZogg+QLq7GHbp2sf2s68M06jhcApb9cwuAc4cea+m1GaluyQUSLhiBcOTSg68rNYhj1F0LCAfBxcM9eOC9dwAjttoo/WpwWtchalQhStOJtFxg1AGgJqR51aGACtAaBfy8PwbshDGgmMxcvpEoox2jupVJA

wVl6fHRWzsXtHgM+1JnurKV5NPB4YkiBzRUdIIg7tZ4Jhu49k11ZsHO3Kc5JUCOs11+eymYVyjjFtjY+wWtgC+W+Cgny/LGssEo5WRF/UhpIkCtU9v9HmVhb3x/OScY5

  1. 第一个参数中使用的字面被捕获为字面类型
  2. 该字面类型可以被验证为在泛型中的有效属性的联合中
  3. 可以使用 Indexed Access 在泛型结构中查找已验证属性的类型
  4. 然后可以应用此类型信息以确保回调函数的参数属于同一类型
type PropEventSource<Type> = {
    on<Key extends string & keyof Type>
        (eventName: `${Key}Changed`, callback: (newValue: Type[Key]) => void ): void;
};

declare function makeWatchedObject<Type>(obj: Type): Type & PropEventSource<Type>;

const person = 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");
    }
})

XdcjF3lS33mYnq1DSyJtWEpteKNkL6ITXsVaGxlWmb+d6Mz14Abz+Kxd0GagcwRlLw7bXxohjGSqdnpqoP9VxA==

qdKoCh8YNV2+3l9HUrCDdxsRHg17WUgqcUciyhgRgihAjMey/arsS83oYkVD2q8nGKtDa2Cx90Fz54GaEpAUDaTsb3VpJknpI8vguv23llgtcrf8XVLFB3sLqRIwehK3NAWljNXOGTsGEtnH2Xc3Apq/o2eAe5gofW1zLE6i7ucKaKXo4D9Fr/7DAU49GkvpgL/qn86csPWlOkBC5xPvM21o8pR5Pw20dqh+/P1C25Sla4aNrCwD/zQdGIeL+EcF8ODY1P4x6hEDUSZbY2xCseAAGC88QhtKbzucvW9dkf5s/71OxrPG+Px5jXtLhyKA+zFopnd0JGcuVBns5xtogMyMQML1DhphmnOlpsXW/zhbun3JNJ7Y6kgUiWVVz4V/qRUYHemm6tvcMWoLY0txtc1/gUF3Spxyaq3mMt2GoNV/43Kk3unWSKZlNeiXR3SCdJmBxdz89+xXfiNe7AXbsfFLyRNxNIkvPzSFFI6Q6MIXo/8umSor/cXEd2UgBP1Pm/D5/AmEqV4R9SXzjJ6Eil4WnDBdj15D3VXIqARs9pMz5WnjD4o3Y9qEgUdHAajjlxR3RfeZAlDRb5fobcVzLrsGxOIajhxnaZCtiOhQb7sc/f0H8cWmpqTikfATmXC7is721P27ynGMzgUhVk5I+/GeLRo0/SW0EQMDeFKGakpRWvR5ppKS+sRYwSa9T3X1/P3kxV5xHrJMysoP8ATVoDZc2ZzsEmGKK0G1Rdj+mEszzIddIbT9NX1oL5S9gDUDEP3scJMjMz924qHGrWLiUQ==

zIDubJpNleAcwDMp/ESldYoKeGD1aQ/BvyMaJ4K7prt3xIyjNUOECKMmLT3MGhWYWLLDigZQBd/j8de2W63GakpBsZusp5hWfSsRoywGcjRY6gVs5w2L+onOHx9mzwz8K3HauGfCk77NHq8kw4f8Iw==

内在字符串操作类型

etq5iL2bXDMge+ZNfnWxM3FqoPzalb1oYz7uoaU08FNFk4hNnuMq7tEINRovWAoidATJUk1gnTkLMNzeNdi48X1UaMJTcvRPzX4ZnduQlPaRpRPfBhz5GuNatb52OqpL2dog9JZTXRFJ9ggN4fzWQkTPZ73k0Pv/ATJIOrSutiXT/SSEivcFIl6DMoJmTScxkQCxFFhX9H7kueOC5Uw/oEtoBOfiCE6wfpVN8XvnSL/y9aTzPKJ6cQi6zlvVAsgJT6o0ojAgdz33BIRFP6dLwf/CQiWF7Q4e8nED4m9YqE4=

Uppercase<StringType>

AHn1JdGdOEJknobFwbY1zHuLusTaMdw0RjVDYJxWZgajlWKOWuXhI7+zq8pYbIrZeQQneoBTO58lQ9bkWQvxSg==

示例

type Greeting = "Hello, world"
type ShoutyGreeting = Uppercase<Greeting>

type ASCIICacheKey<Str extends string> = `ID-${Uppercase<Str>}`
type MainID = ASCIICacheKey<"my_app">

Lowercase<StringType>

AHn1JdGdOEJknobFwbY1zHuLusTaMdw0RjVDYJxWZgYaW0BGtjwKMUDB7wpTkEtkGfehztYsFh4POsmcAtZqjg==

示例

type Greeting = "Hello, world"
type QuietGreeting = Lowercase<Greeting>

type ASCIICacheKey<Str extends string> = `id-${Lowercase<Str>}`
type MainID = ASCIICacheKey<"MY_APP">

Capitalize<StringType>

AHn1JdGdOEJknobFwbY1zH67+5fUgu/Xz6qF9Noy+3W/llrBVhajroVKUeROakOQQYMIfSBXrBAJBas7KcXxAkZkvzzLr5+n1nbLQ79SZ1M=

示例

type LowercaseGreeting = "hello, world";
type Greeting = Capitalize<LowercaseGreeting>;

Uncapitalize<StringType>

AHn1JdGdOEJknobFwbY1zH67+5fUgu/Xz6qF9Noy+3W/llrBVhajroVKUeROakOQ6Fs1lWOGbeaGiDIJs8ZI/ke8wF/T2RKWRHrg3NLe7MY=

示例

type UppercaseGreeting = "HELLO WORLD";
type UncomfortableGreeting = Uncapitalize<UppercaseGreeting>;