6

I have a react app with a keystone.js backend and a graphql api

I have a list of products in keystones.js and a simple graphql query

import gql from "graphql-tag";

export const ALL_PRODUCTS_QUERY = gql`
    query ProductData{
        allProducts{
            id
            price
            description
            name
        }
    }
`

I'm using apollo codegen to generate the types for the graphql so I get

export interface ProductData_allProducts {
  __typename: "Product";
  id: string;
  price: number | null;
  description: string | null;
  name: string | null;
}

export interface ProductData {
  /**
   *  Search for all Product items which match the where clause. 
   */
  allProducts: (ProductData_allProducts | null)[] | null;
}

In React I can list the products and use the types in the code, here I'm using <ProductData>

import { useQuery } from "@apollo/client";
import {ALL_PRODUCTS_QUERY} from '../queries/index'
import { ProductData } from "../generated/ProductData";

const Products = () => {

    const {data, error, loading} = useQuery<ProductData>(ALL_PRODUCTS_QUERY)
    if(loading) return <p>Loading</p>
    if(error) return <p>Error: {error.message}</p> 

    return (
        <div>
            <div>
                {data?.allProducts?.map(product => (
                    <div>{product?.name}</div>
                ))}
            </div>
        </div>
    );
};

export default Products;

Instead of using <div>{product?.name}</div> I would like to create a Product component

import React from 'react';
import { ProductData, ProductData_allProducts } from '../generated/ProductData';

const Product = ({product}:ProductData_allProducts) => {
    return (
        <p>{product.name}</p>
    );
};

export default Product; 

but what should the type be for product here I get an error saying

Property 'product' does not exist on type 'ProductData_allProducts'.    

and on the Products page

import { useQuery } from "@apollo/client";
import {ALL_PRODUCTS_QUERY} from '../queries/index'
import { ProductData } from "../generated/ProductData";
import Product from "./Product";


const Products = () => {

    const {data, error, loading} = useQuery<ProductData>(ALL_PRODUCTS_QUERY)
    if(loading) return <p>Loading</p>
    if(error) return <p>Error: {error.message}</p> 

    return (
        <div>
            <div>
                {data?.allProducts?.map(product => (
                    <Product product={product} />
                ))}
            </div>
        </div>
    );
};

export default Products;    

I now get an error on the product prop

Type '{ product: ProductData_allProducts | null; }' is not assignable to type 'IntrinsicAttributes & ProductData_allProducts'.
  Property 'product' does not exist on type 'IntrinsicAttributes & ProductData_allProducts'.    

So what should the types be on the Product page when passing in the product

3 Answers 3

3
+200

Solution

You can fix the error by changing your code like this:

const Product = ({ product }: { product: ProductData_allProducts }) => {
  return <p>{product.name}</p>;
};

Explanation

The problem was that you typed the props of the component as type ProductComponentProps, all the while you only wanted to type the property props.product as that. So your code basically looked like this:

const Product = (props: ProductData_allProducts) => {
  return (
      <p>{product.name}</p>
  );
};

And as all the properties like name or description where missing, Typescript complained about it. Here is a working codesandbox for you to check out.

Sign up to request clarification or add additional context in comments.

Comments

1

Does the following work for you?

interface ProductComponentProps {
    product: ProductData_allProducts
}


const Product = ({product}: ProductComponentProps) => {
    return (
        <p>{product.name}</p>
    );
};

2 Comments

That does work, but these types are generated by apollo codegen so I thought I shouldn't have to do something like this
where I use the component and pass in the product I get Type 'ProductData_allProducts | null' is not assignable to type 'ProductData_allProducts'. Type 'null' is not assignable to type 'ProductData_allProducts'.
0

You are trying to destructure a property that doesnt exist on the type.
This should work:

type Product = {
  __typename: "Product";
  id: string;
  price: number | null;
  description: string | null;
  name: string | null;
};

const ProductComponent: FC<Product> = ({ name }) => {
  return <p>{name}</p>;
};

export default ProductComponent;

5 Comments

I'm using product instead of name but I'm still getting Property 'product' does not exist on type 'PropsWithChildren<ProductData_allProducts>'
I'm using ProductData_allProducts instead of your Product because they are the same
yea you can use your type ( its the same)
but I still get the same error

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.