ホームページ > 記事 > ウェブフロントエンド > TypeScript データ型のテンプレート リテラルを理解する
TypeScript チームは TypeScript 4.1 をリリースしました。これには、強力なテンプレート リテラル型、マップされた型のキーの再マッピング、および再帰的な条件付き型が含まれています。次の記事では、TypeScript のテンプレート リテラル タイプについて説明します。お役に立てば幸いです。
テンプレート リテラル タイプは文字列リテラル タイプに基づいており、共用体タイプを介して複数のタイプに拡張できます。
これらの構文は JavaScript テンプレート文字列と同じですが、型操作でのみ使用できます。テンプレート リテラル タイプを使用すると、テンプレート内の変数が置き換えられ、新しい文字列リテラルが返されます:
type World = "world"; type Greeting = `hello ${World}`; // type Greeting = "hello world"
テンプレート内の変数が共用体タイプの場合、考えられるすべての文字列リテラル数量が表されます:
type EmailLocaleIDs = "welcome_email" | "email_heading"; type FooterLocaleIDs = "footer_title" | "footer_sendoff"; type AllLocaleIDs = `${EmailLocaleIDs | FooterLocaleIDs}_id`; // type AllLocaleIDs = "welcome_email_id" | "email_heading_id" | "footer_title_id" | "footer_sendoff_id"
テンプレート リテラル内の複数の変数が共用体型の場合、結果は相互乗算されます。たとえば、次の例には 2 2 3 があり、合計 12 種類の型があります。
type AllLocaleIDs = `${EmailLocaleIDs | FooterLocaleIDs}_id`; type Lang = "en" | "ja" | "pt"; type LocaleMessageIDs = `${Lang}_${AllLocaleIDs}`; // type LocaleMessageIDs = "en_welcome_email_id" | "en_email_heading_id" | "en_footer_title_id" | "en_footer_sendoff_id" | "ja_welcome_email_id" | "ja_email_heading_id" | "ja_footer_title_id" | "ja_footer_sendoff_id" | "pt_welcome_email_id" | "pt_email_heading_id" | "pt_footer_title_id" | "pt_footer_sendoff_id"
実際に非常に長い文字列共用体型の場合は、事前に生成することをお勧めしますが、これは短い状況に適しています。
テンプレート リテラルの最も便利な点は、型の内部情報に基づいて新しい文字列を定義できることです。例を見てみましょう:
関数 makeWatchedObject
があり、渡されたオブジェクトに on
メソッドを追加します。 JavaScript では、その呼び出しは次のようになります: makeWatchedObject(baseObject)
、受信オブジェクトは次のとおりであると想定します:
const passedObject = { firstName: "Saoirse", lastName: "Ronan", age: 26, };
この on
メソッドはこの受信時に追加されますオブジェクトの場合、このメソッドは eventName
(string
タイプ) と callBack
(function
タイプ) の 2 つのパラメータを受け入れます。
が次の形式であることを望みます: attributeInThePassedObject "Changed"
。たとえば、passedObject
には属性 firstName
があり、対応する生成された eventName
は firstNameChanged
です。同様に、lastName
は lastNameChanged
に対応し、age
は ageChanged# に対応します##。
この
callBack
は
では、
firstName の値の型は
string であり、
firstNameChanged イベントに対応するコールバック関数は # を受け入れます。 # 渡されます。 #string
型の値。 age
の値の型は number
であり、ageChanged
イベントに対応するコールバック関数は型 number
の値を受け入れます。
戻り値の型は void
型です。
on()。このような署名を使用すると、上記の制約を実装できません。この時点では、テンプレート リテラルを使用できます: <pre class="brush:js;toolbar:false;">// 伪代码
const result = makeWatchedObject(baseObject);
result.on(eventName, callBack);</pre>
この例では、on
メソッドによって追加されたイベント名が追加されていることに注意してください。は
ではなく "firstNameChanged"
であり、コールバック関数によって渡される値は newValue
です。制約は にする必要があります。 string
タイプ。まずは最初のポイントを実装しましょう。 この例では、渡されるイベント名の型がオブジェクト プロパティ名の結合であることを望みますが、各結合メンバーは最後に
Changed
文字で結合されます。 JavaScript では、このような計算を行うことができます:
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}!`); });
テンプレート リテラルでも同様の文字列操作が提供されます: <pre class="brush:js;toolbar:false;">Object.keys(passedObject).map(x => ${x}Changed)</pre>
ここの例では、テンプレート リテラルに It's
ですが、単に
keyof Type と書いてもいいでしょうか?このように書くと、エラーが報告されます: <pre class="brush:js;toolbar:false;">type PropEventSource<Type> = {
on(eventName: `${string & keyof Type}Changed`, callback: (newValue: any) => void): void;
};
/// Create a "watched object" with an &#39;on&#39; method
/// so that you can watch for changes to properties.
declare function makeWatchedObject<Type>(obj: Type): Type & PropEventSource<Type>;</pre>
エラーメッセージから、エラーの理由もわかります。「TypeScript シリーズの Keyof 演算子」では、 がkeyof
演算子 型
が返されますが、テンプレート リテラル変数に必要な型は string |number | bigint | boolean | null | unknown
です。比較のために、もう 1 つのシンボル タイプがあるので、実際には次のように書くこともできます: <pre class="brush:js;toolbar:false;">type PropEventSource<Type> = {
on(eventName: `${keyof Type}Changed`, callback: (newValue: any) => void): void;
};
// Type &#39;keyof Type&#39; is not assignable to type &#39;string | number | bigint | boolean | null | undefined&#39;.
// Type &#39;string | number | symbol&#39; is not assignable to type &#39;string | number | bigint | boolean | null | undefined&#39;.
// ...</pre>
または次のように書くこともできます: <pre class="brush:js;toolbar:false;">type PropEventSource<Type> = {
on(eventName: `${Exclude<keyof Type, symbol>}Changed`, callback: (newValue: any) => void): void;
};</pre>
このメソッドを使用すると、TypeScript はエラーを返します。間違ったイベント名を使用してください:
type PropEventSource<Type> = { on(eventName: `${Extract<keyof Type, string>}Changed`, callback: (newValue: any) => void): void; };テンプレート リテラルによる推論
タイプを単純に使用しています。この制約を実現する鍵は、汎用関数を使用することです: <ul style="list-style-type: disc;">
<li><p>捕获泛型函数第一个参数的字面量,生成一个字面量类型</p></li>
<li><p>该字面量类型可以被对象属性构成的联合约束</p></li>
<li><p>对象属性的类型可以通过索引访问获取</p></li>
<li><p>应用此类型,确保回调函数的参数类型与对象属性的类型是同一个类型</p></li>
</ul><pre class="brush:js;toolbar:false;">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 => {
// (parameter) newName: string
console.log(`new name is ${newName.toUpperCase()}`);
});
person.on("ageChanged", newAge => {
// (parameter) newAge: number
if (newAge < 0) {
console.warn("warning! negative age");
}
})</pre><p>这里我们把 <code>on
改成了一个泛型函数。
当一个用户调用的时候传入 "firstNameChanged"
,TypeScript 会尝试着推断 Key
正确的类型。它会匹配 key
和 "Changed"
前的字符串 ,然后推断出字符串 "firstName"
,然后再获取原始对象的 firstName
属性的类型,在这个例子中,就是 string
类型。
TypeScript 的一些类型可以用于字符操作,这些类型处于性能的考虑被内置在编译器中,你不能在 .d.ts
文件里找到它们。
把每个字符转为大写形式:
type Greeting = "Hello, world" type ShoutyGreeting = Uppercase<Greeting> // type ShoutyGreeting = "HELLO, WORLD" type ASCIICacheKey<Str extends string> = `ID-${Uppercase<Str>}` type MainID = ASCIICacheKey<"my_app"> // type MainID = "ID-MY_APP"
把每个字符转为小写形式:
type Greeting = "Hello, world" type QuietGreeting = Lowercase<Greeting> // type QuietGreeting = "hello, world" type ASCIICacheKey<Str extends string> = `id-${Lowercase<Str>}` type MainID = ASCIICacheKey<"MY_APP"> // type MainID = "id-my_app"
把字符串的第一个字符转为大写形式:
type LowercaseGreeting = "hello, world"; type Greeting = Capitalize<LowercaseGreeting>; // type Greeting = "Hello, world"
把字符串的第一个字符转换为小写形式:
type UppercaseGreeting = "HELLO WORLD"; type UncomfortableGreeting = Uncapitalize<UppercaseGreeting>; // type UncomfortableGreeting = "hELLO WORLD"
从 TypeScript 4.1 起,这些内置函数会直接使用 JavaScript 字符串运行时函数,而不是本地化识别 (locale aware)。
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; }
【相关推荐:javascript学习教程】
以上がTypeScript データ型のテンプレート リテラルを理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。