俺たちは雰囲気でテンプレートリテラルをやっている
MDNより
テンプレートリテラルはバッククォート (`) で区切られたリテラルで、substitutionと呼ばれる埋め込み式が利用できます。
タグなしテンプレートリテラルは文字列となるため、文字列の補間に便利です(エスケープされていない改行が許されるため、複数行の文字列も可能です)。
変数を埋め込んで見やすい形式で文字列を生成できて便利だー、という漠然とした理解の下に雰囲気で使っていた & 何も困らなかったためこれまで調べてこなかった。
が!調べて見るといくつか発見があったため、まとめてみる。
タグなしテンプレートリテラル
おなじみ。改行できたり、式を埋め込めて見やすい形式で文字列を生成できて便利。
// 文字列リテラル
const name = "foo";
console.log("Hello\n" + "World\n" + name + "-san");
// Hello
// World
// foo-san
// テンプレートリテラル
const name = "foo";
console.log(`Hello
World
${name}-san`);
// Hello
// World
// foo-san
テンプレートリテラルは文字列リテラルではない
雰囲気で使っていたために見落としていた点がこちら。
MDNより
テンプレートリテラルは非公式に「テンプレート文字列」と呼ばれることもありますが、文字列リテラルではないので、文字列リテラルが使えるところならばどこでも使えるわけではありません。
使えない場所ってどこよ?と思ったので具体例で理解しよう。
- 例: オブジェクトのプロパティ名
const key3 = "key3"
const obj = {
'key': "value", // 文字列リテラル
key1: "value1", // 識別子
// `key2`: "value2", // テンプレートリテラル(これはエラー)
// `${key3}`: 'value3', // テンプレートリテラル (これもエラー)
};
同様に JSON などスタティックなキー値を要求する場所はNG。
タグ付きテンプレートリテラル
MDNより
タグつきテンプレートリテラルは、リテラルから任意のテキストセグメントの配列と、任意の置換の値を引数として関数(タグ関数)を呼び出します。これは、 DSL に便利です。
無知の頃の感想「これ文法エラーじゃないの???」
わりと初見殺しな気がする。通常、関数はmyFunction(person, age)
みたいな感じにカッコで囲んでパラメータを渡すが、でもMDNにある例のように myTag`That \${person} is a \${age}.` という形式が使え、文字列を生成する前処理として機能する。
let person = "Mike";
let age = 28;
function myTag(strings, personExp, ageExp) {
let str0 = strings[0]; // "That "
let str1 = strings[1]; // " is a "
let str2 = strings[2]; // "."
let ageStr;
if (ageExp > 99) {
ageStr = "centenarian";
} else {
ageStr = "youngster";
}
// テンプレートリテラルを用いて組み立てた文字列を返すこともできます
return `${str0}${personExp}${str1}${ageStr}${str2}`;
}
let output = myTag`That ${person} is a ${age}.`;
console.log(output);
// That Mike is a youngster.
具体的にどこで使われてるの?
(再掲) MDNより
タグつきテンプレートリテラルは、リテラルから任意のテキストセグメントの配列と、任意の置換の値を引数として関数(タグ関数)を呼び出します。これは、 DSL に便利です。
DSL に便利らしい。例えばどのように使われているのか?
- 例1: CSS-in-JS
styled-components では CSS を定義するのにタグ付きテンプレートが使われている。
// Create a Title component that'll render an <h1> tag with some styles
const Title = styled.h1`
font-size: 1.5em;
text-align: center;
color: #BF4F74;
`;
- 例2: Deno dax と Bun Shell
地味に今回テンプレートリテラルを調べようと思ったきっかけ。 dax ではコマンドをテンプレートリテラル形式で記載し、$ 関数内で実行している様子。
#!/usr/bin/env -S deno run --allow-all
import $ from "@david/dax"; // "dax-sh" in Node
// run a command
await $`echo 5`; // outputs: 5
Bun Shell も同様
import { $ } from "bun";
const response = await fetch("https://example.com");
// Use Response as stdin.
await $`cat < ${response} | wc -c`; // 1256
参考