Typescriptタグ付きテンプレート文字列

テンプレート文字列を関数として使用する方法

基本:テンプレート文字列

テンプレートリテラルとも呼ばれるタグ付きテンプレート文字列について説明する前に、一般的なテンプレート文字列について簡単に紹介したいと思います。これが何であるかをすでに知っている場合は、次の章に進んでください。

テンプレート文字列は、Javascript式を含めることができ、複数の行にまたがることができる特殊なタイプの文字列記号です。一般的な文字列の場合のように、二重引用符の代わりにバッククォート文字を使用します。

複数行にわたる文字のスパンに関して、新しい行を作成するには、共通の文字列に文字「n」と組み合わせて円記号を含める必要があります。テンプレート文字列を使用すると、いわば「インライン」で新しい行を作成できます。

// A common string as reference.
const string = "I'm just a string";

// A template string. For Typescript,
// this value is a plain 'string'-type.
const templateString = `I'm just a string as well`;

文字列内の式の可用性も簡単に説明できます。テンプレート文字列は、文字列記号を許可するだけでなく、任意の式を受け入れます。次の例は、私がそれが何を意味するかを示しています。

function greet(name: string) {
  // Here you see an expression
  // *embedded* inside a string.
  return `Hello, ${name}!`;
}

// "Hello, Tom!"
const greeting = greet("Tom");

// One more example, using
// Typescript's 'rest'-operator
// which allowes any number of values
// and provides them as an array,
// in our case of type 'string'.
function greetAll(...names: string[]) {
  return `Hi everybody: ${names.join(", ")}!`;
}

// "Hi everybody: Tom, Luke!"
const greetingForAll = greetAll("Tom", "Luke");

タグ付きテンプレート文字列

この一連の機能だけでもすでに便利ですが、テンプレート文字列を関数として使用することもできます。テンプレート文字列の前にキーワードを置いて「タグ付け」するだけなので、「タグ付きテンプレート文字列」という名前になります。次の例の時間です。

// All previous examples used 'untagged'
// string literals, which means they're 
// practially just a string.
//
// But let's see how we can convert them
// to an acutal function:
function merge(template: TemplateStringsArray, ...params: string[]){
  
  // This needs some explanation:
  //
  // 'template', our first param, contains
  // all strings *inbetween the paramters*,
  // you'll see in a minute what I mean by that.
  //
  // 'params' then is an array of strings
  // that were provided as paramteres to the
  // template string.
  
  // Let's ignore the result for now.
  return "";
}

const what = "test";

// Here's the tagged template string in action.
// The tag is the function name, and like a 
// function the tagged template string can be called.
//
// Let's destruct how this will look like
// in the function defined above.
//
// 'template' = ["Just a", ""];
// 'params'   = ["test"]
const result = merge`Just a ${what}`;

// As you can see, the function splits the string
// into the string-only parts and the expressions.

ご覧のとおり、構文は非常に興味深く、最初に使用したときは少し異質に見えるかもしれません。タグ付けされたテンプレート文字列を実装する必要があるユースケースはおそらくそれほど多くありませんが、それでも私たちはそれを試すことができます。次の最後の例では、いくつかのケーススタディをまとめました。ご覧のとおり、タグ付きテンプレート文字列はジェネリックスで自然に使用でき、特定の要件を実装するためのいくつかの興味深いオプションを開くことができます。

// 
// Generic
//
// Tagged template literals can be generic, too.
function generic<T>(template: TemplateStringsArray, ...params: T[]){
    return template.join(",") + params.join(",")
}

// "A value: ,test"
console.log(generic<string>`A value: ${"test"}`);

//
// Generic (with super powers)
//
// You can specify each type and 
// also limit the number of params!
function coalesce<A, B, C>(template: TemplateStringsArray, ...params: [A, B, C]){
    return template.join(",") + params.join(",")
}

// ", - , - ,value,0,true" 
const res = coalesce<string, number, boolean>`${"value"} - ${0} - ${true}`;

//
// Different return type
//
// Also, tagged literal types don't 
// only have to return strings.
const preview = (template: TemplateStringsArray, ...params: number[]) 
  => (template2: TemplateStringsArray, ...params2: string[])
  => {
    return "what?";
}

// Note the two pairs of backticks
// after each other, we're just calling
// the returned tagged template string
// form our first one!
console.log(preview`${0}``${"a"}`);

Typescriptの機能だけでなくJavascriptの機能の1つへのこのかなり迅速なフィールドトリップを楽しんでいただけたと思います。テンプレート文字列はコードベースで一般的なものである可能性が高く、タグ付きテンプレート文字列はおそらくそうではないため、このようなニッチな機能について詳しく知ることは興味深いことです。

提案

関連する

追加事項

言語