Me preguntaba si puedo tener tipos condicionales en TypeScript.
Actualmente tengo la siguiente interfaz:
interface ValidationResult { isValid: boolean; errorText?: string; }
Pero quiero eliminar errorText
y solo tenerlo cuando isValid
es false
como una propiedad requerida .
Desearía poder escribirlo como la siguiente interfaz:
interface ValidationResult { isValid: true; } interface ValidationResult { isValid: false; errorText: string; }
Pero como sabes, no es posible. Entonces, ¿cuál es tu idea sobre esta situación?
Una forma de modelar este tipo de lógica es usar un tipo de unión, algo como esto
interface Valid { isValid: true } interface Invalid { isValid: false errorText: string } type ValidationResult = Valid | Invalid const validate = (n: number): ValidationResult => { return n === 4 ? { isValid: true } : { isValid: false, errorText: "num is not 4" } }
Luego, el compilador puede reducir el tipo en función de la bandera booleana
const getErrorTextIfPresent = (r: ValidationResult): string | null => { return r.isValid ? null : r.errorText }
Para evitar crear múltiples interfaces que solo se usan para crear una tercera, también puede alternar directamente, con un type
en su lugar:
type ValidationResult = { isValid: false; errorText: string; } | { isValid: true; };
La unión demostrada por errores es cómo recomiendo manejar esto. No obstante, Typescript tiene algo conocido como " tipos condicionales ", y pueden manejar esto.
type ValidationResult<IsValid extends boolean = boolean> = (IsValid extends true ? { isValid: IsValid; } : { isValid: IsValid; errorText: string; } ); declare const validation: ValidationResult; if (!validation.isValid) { validation.errorText; }
Este ValidationResult
(que en realidad es ValidationResult<boolean>
debido al parámetro predeterminado) es equivalente a la unión producida en la respuesta de errores o en la respuesta de CertainPerformance , y se puede usar de la misma manera.
La ventaja aquí es que también podría pasar un valor conocido de ValidationResult<false>
, y luego no tendría que probar isValid
ya que se sabría que es false
y errorString
se sabría que existe. Probablemente no sea necesario para un caso como este, y los tipos condicionales pueden ser complejos y difíciles de depurar, por lo que probablemente no deberían usarse innecesariamente. Pero se podía, y eso parecía digno de mención.