Template-Strings mit Typoskript-Tags

So verwenden Sie Vorlagenzeichenfolgen als Funktionen

Die Grundlagen: Template-Strings

Bevor ich über mit Tags versehene Template-Strings, auch Template-Literale genannt, spreche, möchte ich nur eine kurze Einführung in Template-Strings im Allgemeinen geben. Zögern Sie nicht, zum nächsten Kapitel zu springen, wenn Sie bereits wissen, worum es geht.

Template-Strings sind eine spezielle Art von String-Symbolen, die Javascript-Ausdrücke enthalten und sich über mehrere Zeilen erstrecken können. Sie verwenden die Backtick-Zeichen anstelle von doppelten Anführungszeichen, wie es bei üblichen Strings der Fall ist.

Bei der Überbrückung von Zeichen über mehrere Zeilen muss ein gemeinsamer String einen Backslash in Kombination mit dem Zeichen „n“ enthalten, um eine neue Zeile zu bilden. Mit Template-Strings können Sie sozusagen einfach eine neue Zeile „inline“ anlegen.

// 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`;

Auch die Verfügbarkeit von Ausdrücken innerhalb eines Strings lässt sich schnell erklären. Anstatt nur Zeichenfolgensymbole zuzulassen, akzeptieren Vorlagenzeichenfolgen beliebige Ausdrücke. Das folgende Beispiel zeigt, was ich damit meine.

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");

Getaggte Vorlagenstrings

Dieser Satz von Funktionen allein wäre schon schön, aber auch Template-Strings können als Funktionen verwendet werden. Sie setzen einfach ein Schlüsselwort vor den Template-String, um ihn zu „taggen“, daher der Name „getaggte Template-Strings“. Zeit für das nächste Beispiel.

// 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.

Wie Sie sehen, sieht die Syntax beim ersten Arbeiten recht interessant und vielleicht sogar etwas fremd aus. Es gibt wahrscheinlich nicht viele Anwendungsfälle, in denen Sie mit Tags versehene Vorlagenstrings implementieren müssen, aber wir können trotzdem damit herumspielen. Im folgenden und letzten Beispiel habe ich einige Fallstudien zusammengestellt. Wie Sie sehen werden, können getaggte Template-Strings natürlich mit Generics verwendet werden und eröffnen einige interessante Möglichkeiten, bestimmte Anforderungen zu implementieren.

// 
// 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"}`);

Ich hoffe, Ihnen hat diese kurze Exkursion in eine der Funktionen von Javascript und Typescript gefallen. Template-Strings sind höchstwahrscheinlich eine häufige Sache in Ihrer Codebasis, getaggte Template-Strings wahrscheinlich nicht, daher ist es interessant, mehr über solche Nischenfunktionen zu erfahren.

Vorschläge

Verwandt

Anhang

Sprachen