Frecuentemente los checks en un type condicional nos proporcionan cierta información adicional. De la misma manera que al usar restricciones como las unions combinados con generics, el uso de tipos condicionales nos permiten también definir restricciones.
type MensajeDe<T> = T["mensaje"];
// esto generará un error debido a que no sabemo si el tipo tiene una propiedad mensaje
Podemos cambiar nuestro indexed type de la siguiente forma para prevenir este error.
type MensajeDe<T extends { mensaje: unknown }> = T["mensaje"];
¿Qué sucede si deseamos que MensajeDe
pueda tomar cualquier valor, pero que never
sea el valor por default cuando la propiedad no exista?
Podemos solucionar esto utilizando conditional types.
type MensajeDe<T> = T extends { mensaje: unknown } ? T["mensaje"] : never;
type Mensaje1 = MensajeDe<{ mensaje: string }>;
// type = string
type Mensaje2 = MensajeDe<{ mensaje: number }>;
// type = number
type Mensaje3 = MensajeDe<{}>;
// type = never
Cuando el resultado de evaluar el condicional es positivo, este nos arroja un tipo dependiendo de la propiedad mensaje
que siempre existirá.
Obtener el tipo a partir de un arreglo
En el siguiente ejemplo, creamos un tipo llamado Flatten
que usa el tipo homogéneo almacenado en un arreglo o un tipo por default.
type Flatten<T> = T extends any[] ? T[number] : T;
type T1 = Flatten<number[]>;
// type number
type T2 = Flatten<number>;
// type = number
Cuando
Flatten
es utilizado, utiliza un indexed type cuando la parte verdadera se cumple, es decir cuando estamos utilizando un arreglo, de lo contrario hace referencia al tipo utilizado directamente.