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

    ↑↓ mover · ⏎ abrir · esc cerrar

    Concepto 6 de 12

    Tipos condicionales

    Un tipo condicional es el `if` a nivel de tipos. La pregunta que plantea es siempre la misma: ¿es el lado izquierdo asignable al derecho? No «¿son iguales?», no «¿es una instancia de?» — asignable, y en un solo sentido.

    Asignabilidad, no igualdad

    type A = 'hello' extends string ? true : false   // true
    type B = string extends 'hello' ? true : false   // false
    type C = never extends string ? true : false     // true — never fits anywhere
    type D = { a: 1; b: 2 } extends { a: 1 } ? true : false  // true

    Un tipo más estrecho es asignable a uno más amplio, así que la prueba tiene dirección. Un objeto con propiedades de más es asignable a otro con menos, y por eso `extends` no sirve para comprobar que dos tipos objeto tengan la misma forma.

    Cuando de verdad necesitas «el mismo tipo», necesitas el helper `Equal` sobre el que se apoya cada comprobación de este sitio — dos condicionales diferidos comparados por identidad, más estricto que la asignabilidad en ambos sentidos.

    Las ramas se prueban en orden

    type Describe<T> = T extends (...args: never[]) => unknown
      ? 'function'
      : T extends unknown[]
        ? 'array'
        : T extends object
          ? 'object'
          : 'primitive'

    Los casos más estrechos deben ir primero. Funciones y arrays son ambos objetos, así que probar `extends object` pronto se los tragaría — la causa clásica de un `DeepReadonly` que destruye en silencio cada función que toca.

    El error más común

    // Intent: is T exactly string?
    type IsString<T> = T extends string ? true : false
    
    IsString<'hello'>  // true — but 'hello' is not string, it is narrower
    IsString<any>      // boolean — any matches both branches at once

    `extends` responde a «cabe en», así que todo literal de cadena pasa una prueba de `string`. Y `any` es asignable a todo, así que un condicional con `any` devuelve la unión de ambas ramas — un resultado que casi nunca es el que se pretendía.

    Ejercicio

    Responde `true` cuando `T` sea `string`, y `false` en caso contrario.

    Pruébalo

    2
    • IsString<'a'>
      true
    • IsString<number>
      false

    Para recordar

    Los condicionales preguntan por asignabilidad y prueban las ramas en orden. Lo estrecho primero, y recurre a `Equal` en cuanto necesites igualdad real.

    Se practica en