Cadenas de plantillas con etiquetas mecanografiadas

Cómo usar cadenas de plantillas como funciones

Conceptos básicos: cadenas de plantillas

Antes de hablar sobre las cadenas de plantilla etiquetadas, también llamadas literales de plantilla, solo quiero dar una introducción rápida a las cadenas de plantilla en general. No dude en pasar al siguiente capítulo si ya sabe de qué se trata.

Las cadenas de plantilla son un tipo especial de símbolos de cadena que pueden contener expresiones Javascript y abarcar varias líneas. Usan los caracteres de acento inverso en lugar de comillas dobles, como es el caso de las cadenas comunes.

Con respecto a la extensión de caracteres en varias líneas, una cadena común debe contener una barra invertida en combinación con el carácter "n" para crear una nueva línea. Con cadenas de plantilla, simplemente puede crear una nueva línea "en línea", por así decirlo.

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

La disponibilidad de expresiones dentro de una cadena también se puede explicar rápidamente. En lugar de permitir simplemente símbolos de cadena, las cadenas de plantilla aceptan expresiones arbitrarias. El siguiente ejemplo muestra lo que quiero decir con eso.

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

Cadenas de plantilla etiquetadas

Este conjunto de características por sí solo ya sería bueno, pero las cadenas de plantillas también se pueden usar como funciones. Simplemente coloque una palabra clave delante de la cadena de plantilla para "etiquetarla", de ahí el nombre "cadenas de plantilla etiquetadas". Es hora del siguiente ejemplo.

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

Como puede ver, la sintaxis parece bastante interesante y tal vez incluso un poco extraña cuando se trabaja con ella por primera vez. Probablemente no haya muchos casos de uso que requieran que implementes cadenas de plantillas etiquetadas, pero no obstante, podemos jugar con ellas. En el siguiente y último ejemplo, he reunido algunos casos de estudio. Como verá, las cadenas de plantillas etiquetadas se pueden usar naturalmente con genéricos y abren algunas opciones interesantes para implementar ciertos requisitos.

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

Espero que haya disfrutado de este viaje de campo bastante rápido a una de las funciones de JavaScript y Typecript. Las cadenas de plantilla probablemente sean algo común en su base de código, las cadenas de plantilla etiquetadas probablemente no, por lo que es interesante obtener más información sobre estas características de nicho.

Sugerencias

Relacionados

Adenda

Idiomas