Typescript definition of data coming from GraphQL and Apollo Client

162 Views Asked by At

I am working on a project with Typescript GraphQL Apollo Client and Next.js in the front end and Strapi on the back end. Currently, the code works, but I am having issues with the type definition of the query object from GraphQL. It works fine if I just put any, but I wonder what might be the best approach to it. This is the getStaticProps function where I get the query from GraphQL and Strapi:

export const getStaticProps: GetStaticProps = async ({ params }) => {
    const { data } = await client.query({
        query: gql`
            query Campaign {
                campaigns {
                    data {
                        id
                        attributes {
                            Title
                            URLSlug
                            Ads {
                                ... on ComponentAdsSingleImageOrVideo {
                                    Headline
                                    PrimaryText
                                    CTAButtonLink
                                    singleImageOrVideoCTA: CTAButtonLinkType
                                    ImageVideoOrSlider {
                                        data {
                                            id
                                            attributes {
                                                ext
                                                width
                                                url
                                                height
                                                formats
                                            }
                                        }
                                    }
                                    singleImageOrVideoPlacement: Placement
                                    singleImageOrVideoPlatform: Platform
                                    Description
                                }
                                ... on ComponentAdsCarousel {
                                    id
                                    PrimaryText
                                    carouselPlacement: Placement
                                    carouselPlatform: Platform
                                    CTAButtonLink
                                    carouselCTA: CTAButtonLinkType
                                    ImageOrVideo {
                                        data {
                                            attributes {
                                                width
                                                url
                                                height
                                            }
                                        }
                                    }
                                    CarouselCards {
                                        id
                                        Headline
                                        Description
                                        WebsiteURL
                                        CardImage {
                                            data {
                                                id
                                                attributes {
                                                    height
                                                    url
                                                    width
                                                }
                                            }
                                        }
                                    }
                                }
                                ... on ComponentAdsCarouselCard {
                                    id
                                    Headline
                                    Description
                                    WebsiteURL
                                    CardImage {
                                        data {
                                            attributes {
                                                width
                                                url
                                                height
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        `,
    });

    if (!params || !params.id) {
        return { props: {} };
    }

    const campaign = data.campaigns.data.find((d: StrapiProps) => d.attributes.URLSlug === (params.id as string));

    return {
        props: { campaign },
    };
};

This is the type definition I used on it:

export interface StrapiProps {
    attributes: {
        client: {
            data: {
                attributes: {
                    Name: string;
                };
            };
        };
        Title: string;
        URLSlug: string;
        Ads: [
            {
                Headline: string;
                PrimaryText: string;
                CTAButtonLink: string;
                CTAButtonLinkType: string[];
                ImageVideoOrSlider: {
                    data: {
                        id: string | number;
                        attributes: {
                            ext: string;
                            width: number;
                            url: string;
                            height: number;
                        };
                    }[];
                };
                Placement: string;
                Platform: string;
                Description: string;
            },
            {
                data: {
                    attributes: {
                        id: string | number;
                        Platform: string;
                        PrimaryText: string;
                        CTAButtonLink: string;
                        CTAButtonLinkType: string[];
                        ImageOrVideo: {
                            data: {
                                attributes: {
                                    width: number;
                                    url: string;
                                    height: string;
                                };
                            };
                        };
                    };
                };

                CarouselCards: {
                    data: {
                        attributes: {
                            id: string | number;
                            Headline: string;
                            Description: string;
                            WebsiteURL: string;
                            Image: {
                                data: {
                                    attributes: {
                                        width: number | string;
                                        url: string;
                                        height: number | string;
                                    };
                                };
                            };
                        };
                    }[];
                };
            },
            {
                data: {
                    attributes: {
                        id: string | number;
                        Headline: string;
                        Description: string;
                        WebsiteURL: string;
                        Image: {
                            data: {
                                attributes: {
                                    width: number | string;
                                    url: string;
                                    height: number | string;
                                };
                            };
                        };
                    };
                };
            }
        ];
    };
}

Till here the code works fine, perhaps somebody would advise me how to define it better though. The issue occurs when I use the data on another page like that:

const platform = campaign.attributes.Ads.filter((i: any) =>
        (i.singleImageOrVideoPlatform === 'Facebook' || i.CarouselPlatform === 'Facebook') && (i.singleImageOrVideoPlacement === 'Feeds' || i.CarouselPlatform === 'Feeds') ? true : false
    );

Campaign has all the types defined but now platform it hasn't. So, if then I want to do a map in the tsx like that:

{platform.map((camp: any) => (

I have to use any on both filter and map, otherwise, the code breaks with this error. enter image description here

I am looking for advice on how to properly define and use typescript in this case. Should I create a new interface for both cases? Perhaps it could be an issue with the union types of Apollo from what I read. Thanks in advance.

0

There are 0 best solutions below