Por ejemplo, tengo un código de este tipo:
interface Subscriber { reviewData: string | string[] hasArray: boolean; } const reviews = ["Good", "Not bad"]; const subscriber: Subscriber = { reviewData: reviews, hasArray: Array.isArray(reviews) } if (subscriber.hasArray) { subscriber.reviewData.forEach(console.log); } else { console.log(subscriber.reviewData); }
Por supuesto, TypeScript se quejará en subscriber.reviewData.forEach(console.log);
diciendo que no puede definir si es una matriz o solo una cadena porque no hay suficiente tipo de protección en la condición subscriber.hasArray
.
No quiero escribir siempre Array.isArray(subscriber.reviewData)
porque voy a usar esta lógica en muchos otros lugares.
He oído hablar de is
, pero ese no es realmente el caso en mi escenario porque usar is
implica que debe tener una función y pasarle algún argumento.
¿Cómo puedo lograr el resultado deseado?
Si desea poder usar hasArray
como una forma de determinar si reviewData
es una string[]
o una string
, entonces realmente desea que Subscriber
sea un tipo de unión discriminado en lugar de una interfaz. Su interfaz permitiría {reviewData: "", hasArray: true}
, por lo que el compilador no puede descartar la posibilidad. Con una unión discriminada, puede tener una propiedad discriminante que verifica para restringir el tipo de todo el objeto:
type Subscriber = { reviewData: string[] hasArray: true; } | { reviewData: string hasArray: false; }
En este caso hasArray
es la propiedad discriminante de un literal booleano de tipo true
o false
.
Entonces, dado un Subscriber
:
const subscriber: Subscriber = Math.random() < 0.5 ? { reviewData: "Good", hasArray: false } : { reviewData: ["Who", "Cares"], hasArray: true };
Podemos verificarlo de la manera que desee sin error del compilador:
if (subscriber.hasArray) { subscriber.reviewData.forEach(console.log); } else { console.log(subscriber.reviewData.toUpperCase()); }