Saltar al contenido
webtype.orgwebtype.orgDoce conceptos · 9/12

    ↑↓ mover · ⏎ abrir · esc cerrar

    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.

    Ejercicio

    Construye un nombre de manejador: `click` se convierte en `onClick`.

    Pruébalo

    2
    • Handler<'click'>
      'onClick'
    • Handler<'focus' | 'blur'>
      'onFocus' | 'onBlur'

    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