Discriminate Types
Una unión de tipo discriminado es cuando se utiliza el
análisis de flujo de código para reducir un conjunto de
objetos potenciales a un objeto específico.
Este patrón funciona muy bien para conjuntos de objetos
similares con una cadena o constante numérica diferente,
por ejemplo: una lista de eventos con nombre, o conjuntos
de objetos versionados.
// Cuando el evento entra en esta función, podría ser
cualquiera de los dos tipos potenciales.
type TimingEvent = { name: "start"; userStarted: boolean } | { name: "closed"; duration: number };
// Este patrón es el mismo con los números que podemos usar
como el discriminador.
En este ejemplo, tenemos una unión discriminante y un
estado de error adicional que manejar.
const handleEvent = (event: TimingEvent) => {
// Mediante el uso de un interruptor en event.name el
// análisis de flujo de código de TypeScript puede
// determinar que un objeto sólo puede ser representado
// por un tipo en la unión.
switch (event.name) {
case "start":
// Esto significa que puedes acceder con seguridad a
// userStarted porque es el único tipo dentro de
// TimingEvent donde el nombre es "start".
const initiatedByUser = event.userStarted;
break;
case "closed":
const timespan = event.duration;
break;
}
};
// Es mejor usar una declaración switch en lugar de
declaraciones if, porque puedes asegurarte de que todas
las partes de la unión son revisadas. Hay un buen patrón
para esto usando el tipo `never` en el manual:
https://www.typescriptlang.org/docs/handbook/advanced-types.html#discriminated-unions
type APIResponses = { version: 0; msg: string } | { version: 1; message: string; status: number } | { error: string };
const handleResponse = (response: APIResponses) => {
// Maneja el caso de error, y luego retorna
if ("error" in response) {
console.error(response.error);
return;
}
// TypeScript ahora sabe que APIResponse no puede ser el
// tipo de error. Si fuera el error, la función habría
// retornado. Puede verificar esto pasando el cursor sobre
// response a continuación.
if (response.version === 0) {
console.log(response.msg);
} else if (response.version === 1) {
console.log(response.status, response.message);
}
};