Búsqueda de sitios web

Cómo obtener el tipo de unión anidada en TypeScript


Estoy usando graphql codegen que generó este tipo para mí:

export type GetOffersForMembershipQuery = {
  __typename?: "Query";
  offers:
    | { __typename?: "BaseError" }
    | {
        __typename?: "QueryOffersSuccess";
        data: Array<{
          __typename?: "Offer";
          title: string;
          details: string;
          identifier: string;
          merchant?: {
            __typename?: "Merchant";
            logoImageUrl?: string | null;
          } | null;
        }>;
      }
    | { __typename?: "ValidationError" };
};

Quiero extraer el tipo de data aquí. ¿Cómo puedo hacer esto?

Intenté hacer simplemente:

GetOffersForMembershipQuery["offers"]["data"];

Pero, por supuesto, el problema es que ["data"] no existe si el __typename no es "QueryOffersSuccess".

Respuesta #1

Puedes usar Extract para extraer solo los miembros de una unión que extiende un tipo.

type MyData =
  Extract<GetOffersForMembershipQuery['offers'], { data: unknown }>['data']

El tipo de utilidad Extract está documentado como:

type Extract<T, U> = T extends U ? T : never
// Extract from T those types that are assignable to U

Entonces, en este caso, extrae todos los miembros que se puedan asignar a { data: unknown }, que en este caso es el único miembro con la propiedad data, lo que hace que sea seguro acceder a esa propiedad.

Ver el patio de recreo

Respuesta #2

ACTUALIZACIÓN

Empecé a trastear, y me pregunto si esto hace lo que necesitas?

type test = GetOffersForMembershipQuery['offers'] extends { __typename: infer U } ? U : never
type t2 = test['data']

Respuesta Original

Creo que esta respuesta tiene todo lo que necesitas. Empecé a jugar con NonNullable<T> para que funcionara, pero eso es para obtener tipos opcionales, y aunque funciona con anidamiento cuando se encadena, esto todavía muestra un error:

type Response = NonNullable<NonNullable<GetOffersForMembershipQuery["offers"]>["data"]>;

La razón por la que eso todavía no es suficiente, es que tu tipo también es un Union. Sin embargo, busqué un poco por ti, y creo que el enlace que compartí contiene todas las partes necesarias.