Saltar al contenido
webtype.orgDoce conceptos · 9/12

Concepto 9 de 12

Tipos de literal de plantilla

Los tipos de literal de plantilla permiten al compilador construir y emparejar cadenas. Combinados con `infer` y recursión pueden analizar — así una ruta se convierte en un objeto de parámetros, y así se comprueban en compilación las claves i18n y los nombres de columna de un ORM.

Construir y convertir a cadena

type Greeting = `hello ${string}`
type Event = `on${'Click' | 'Focus'}`   // 'onClick' | 'onFocus'
type AsText = `${42}`                    // '42'

// Interpolating a union multiplies out every combination.
type Cell = `${'a' | 'b'}${1 | 2}`       // 'a1' | 'a2' | 'b1' | 'b2'

Interpolar una unión produce el producto cartesiano, que crece rápido — TypeScript limita el resultado a 100.000 miembros y da error por encima. Convertir un número con `` `${N}` `` es la forma estándar de transformar un problema aritmético en uno de texto.

El emparejamiento está anclado y es ávido por la izquierda

type StartsWith<S, P extends string> = S extends `${P}${string}` ? true : false
type EndsWith<S, P extends string> = S extends `${string}${P}` ? true : false
type Contains<S, P extends string> = S extends `${string}${P}${string}` ? true : false

// Greedy from the left: Head binds the SHORTEST prefix that works.
type Split1<S> = S extends `${infer Head}-${infer Tail}` ? [Head, Tail] : never
type X = Split1<'a-b-c'>   // ['a', 'b-c']

Un patrón debe emparejar toda la cadena, así que donde pongas `${string}` es donde permites holgura. Holgura delante significa «contiene», detrás «empieza por», y a ambos lados significa que has escrito sin querer un test de subcadena.

Los cuatro tipos intrínsecos de mayúsculas

Uppercase<'abc'>      // 'ABC'
Lowercase<'ABC'>      // 'abc'
Capitalize<'abc'>     // 'Abc'
Uncapitalize<'Abc'>   // 'abc'

Estos cuatro están implementados de forma nativa en el compilador y no tienen código TypeScript. Recurre a ellos antes de escribir una recursión carácter a carácter — `CamelCase` y compañía son unas pocas líneas con ellos y una pesadilla sin ellos.

El error más común

type Replace<S extends string, From extends string, To extends string> =
  S extends `${infer H}${From}${infer T}` ? `${H}${To}${T}` : S

Replace<'abc', '', 'x'>   // 'xabc' — not 'abc'

La cadena vacía cabe entre dos caracteres cualesquiera, así que una aguja vacía encaja de inmediato con `H` vacío. Es el `null` de los tipos de literal de plantilla: encaja en todas partes y rompe en silencio los patrones que asumen que encajar significa haber encontrado algo.

Para recordar

Los patrones están anclados por ambos extremos y son ávidos por la izquierda. Dónde permites holgura decide qué estás preguntando de verdad, y la cadena vacía siempre es el caso límite.

Se practica en