Tipos de literales de plantilla en TypeScript

En este artículo, analizaremos más de cerca los tipos de literales de plantilla y cómo puede aprovecharlos en sus actividades diarias como desarrollador.

Entonces, ¿qué son los tipos de literales de plantilla?

Tipos de literales

Para comprender qué son los tipos de literales de plantilla, primero debemos echar un vistazo breve a los tipos de literales. Los tipos literales nos permiten definir tipos que son más específicos, en lugar de algo generalizado como una cadena o un número.

Digamos que tienes un interruptor; puede tener el valor de encendido o apagado. Una forma de definir los tipos de esto es usar tipos literales, dándole el tipo de On o Off :

type Switch = "On" | "Off"

En el caso anterior, el valor de cualquier variable de tipo Switch solo puede ser On o Off :

const x: Switch = "On"
const y: Switch = "Off"

Si intentó asignar cualquier otro valor que no sea On o Off , mecanografiado arrojará un error:

Tipos de literales de plantilla

Los tipos literales de plantilla se basan en esto, lo que le permite crear nuevos tipos usando una plantilla y puede expandirse a muchas cadenas diferentes usando uniones. Esto funciona como una plantilla literal/cadenas, pero en lugar de concatenar para formar cadenas, se concatena para formar tipos.

const variable = "string";
type tVariable = "string";

// this results to a variable
const val = `This is a concatenated ${variable}`

// while this results to type
type X = `This is a concatenated ${tVariable}`

Como puede ver, son similares en sintaxis aparte de cómo se definen, siendo el primero una variable y el segundo un tipo. El tipo de la primera definición será cadena, mientras que la segunda será de tipo This is a concatenated string y una variable de ese tipo solo se puede asignar a esa cadena.

Si tomamos nuestro ejemplo anterior de tipo Switch, es posible que queramos tener una función que devuelva el estado del switch, es decir, Switch is On o Switch is Off , y tenerlo fuertemente tipado, en el sentido de que solo puede devolver solo esas cadenas. Con Template Literal Types, podemos definir esto de la siguiente manera:

type Switch = "On" | "Off"

const x: Switch = "On"
const y: Switch = "Off"

type SwitchStatus = `Switch is ${Switch}`;

Y esto a cambio nos da los tipos:Switch is On y Switch is Off :

Usar para construir tipos para coordenadas de elementos de cuadrícula

Digamos que estamos trabajando con un sistema de cuadrícula y queremos realizar una tarea en varias casillas de nuestra cuadrícula, como colocar algo en una casilla específica dadas sus coordenadas. Sería bueno si pudiéramos escribirlo fuertemente y asegurarnos de no especificar valores fuera de la cuadrícula.

Por ejemplo, si tuviéramos una cuadrícula cuya longitud fuera de 3 cajas más pequeñas a cada lado de la caja. Esto hace que tengamos 9 cajas más pequeñas encajando en nuestra caja grande. Podemos usar tipos literales para crear un tipo para cada uno de nuestros cuadros, siendo el tipo su posición en la cuadrícula. Entonces, el primero obtiene L1-H1 y el último obtiene L3-H3 tipos, como se muestra a continuación.

type SquareBoxes = "L1-H1" | "L1-H2" | "L1-H3" | "L2-H1" | "L2-H2" | "L2-H3" | "L3-H1" | "L3-H2" | "L3-H3";

Esos son muchos tipos para crear a mano, incluso para una pequeña cuadrícula de 9 cajas. Pero, con los tipos de literales de plantilla, podríamos definir solo el tipo de la longitud de un lado y usar literales de cadena de plantilla para expandir el resto de los tipos:

type length = "1" | "2" | "3";

type SmallerBoxes = `L${length}-H${length}`

Y esto arrojaría el mismo resultado que antes:

Esto hace que nuestro trabajo sea más fácil y más versátil, ya que si las cajas más pequeñas alguna vez aumentaron o disminuyeron, solo necesita ajustar el tamaño de la longitud.

// 16 boxes
type length = "1" | "2" | "3" | "4";

// 25 boxes
type length = "1" | "2" | "3" | "4" | "5";

// 4 boxes
type length = "1" | "2";

Combinación con genéricos

Podemos combinar tipos de literales de plantilla con genéricos para lograr un efecto asombroso. Tomemos con un Tipo de Person , que tiene dos propiedades - name y age .

type Person = {
    name: string;
    age: number;
}

Queremos agregar dos métodos a llamar para actualizar los valores de name o age es decir, nameChanged o ageChanged . Podemos crear un nuevo tipo, que tomará el tipo Person como genérico, y para cada propiedad de tipo Person , agregaremos nuevas propiedades con Changed agregó las propiedades originales de tipo Persona, es decir, nameChanged y ageChanged . Usaremos tipos de literales de plantilla para crear una nueva propiedad agregando Changed al nombre de la propiedad.

type WithPersonChangedEvents<Type> = {
    [Property in keyof Type as `${string & Property}Changed`]: (newValue: Type[Property]) => void;
} & Type;

Ahora, podemos usar nuestros dos Tipos (Persona y WithPersonChangedEvent ) arriba:

const person: WithPersonChangedEvents<Person> = {
    name: "Name",
    age: 20,
    nameChanged: (newName) => console.log(newName),
    ageChanged: (newAge) => console.log(newAge),
};

person.ageChanged(21); // Logs: 21
person.nameChanged("new Name"); // Logs: "new Name"

Y como puede ver, nuestro objeto - person tiene 4 propiedades, siendo 2 los métodos agregados.

Conclusión

Hemos aprendido acerca de los tipos de literales de plantilla en TypeScript y cómo se construyen sobre los tipos de literales superiores para brindarle aún más flexibilidad al definir tipos. También hemos analizado diferentes casos de uso, como en una definición de tipo de sistema de cuadrícula para diferentes coordenadas de cajas y combinándolas con genéricos para definir propiedades adicionales para un objeto.

Recursos

  • Creación de tipos a partir de tipos:enlace.
  • Documentación de tipos de literales de plantilla:enlace.
  • Literales de plantilla (cadenas de plantilla) - Enlace.
  • Tipos y burlas - Mecanografiado - Enlace.
  • Transformación de tipos en TypeScript con tipos de utilidad:enlace.

Discutir este artículo