2

I went through several similar questions but wasn't able to get anywhere in solving this. I was following along with a tutorial from 2019 and I'm having trouble figuring out the right way to do the same thing in 2020. Here's the line I'm getting an error on:

ERROR: 'HotelsQuery' only refers to a type, but is being used as a namespace here.ts(2702)

type IHotelsProps = HotelsQuery.Props<IHotelsBaseProps> & RouteComponentProps;

I'm passing HotelsQuery from my generatedModels file, defined as:

export type HotelsQuery = (
  { __typename?: 'Query' }
  & { hotels?: Maybe<(
    { __typename?: 'HotelTypeConnection' }
    & { edges: Array<Maybe<(
      { __typename?: 'HotelTypeEdge' }
      & { node?: Maybe<(
        { __typename?: 'HotelType' }
        & Pick<HotelType, 'id' | 'title' | 'body'>
      )> }
    )>> }
  )> }
);

And the class it's being passed to:

class Hotels extends React.Component<IHotelsProps, IHotelsState> {
    constructor(props: IHotelsProps) {
        super(props);
        const query = queryString.parse(props.location.search);
        this.state = {
            searchQuery: query && query.search
            ? query.search.toString() : undefined
        };
    }

    public render() {
        const { searchQuery } = this.state;
        const { data } = this.props;

        return (
            <Row>
                <Col span={12} offset={6}>
                    <Divider>Add Hotel</Divider>
                    <Divider>Hotels</Divider>
                    <Input.Search
                        placeholder="Search..."
                        enterButton="Search"
                        defaultValue={searchQuery}
                        onChange={this.handleSearchQueryChange}
                        onSearch={this.handleSearch}
                    />
                    {data!.loading ? (
                        <Spin style={{ marginTop: 16, display: 'block' }} /> )
                        : (
                            <div>
                                {data!.notes!.edges.map(edge => (
                                <Card
                                    key={edge!.node!.id}
                                    style={{ marginTop: 16 }}
                                    actions={[
                                        <Icon
                                            type="delete"
                                            key={edge!.node!.id}
                                            onClick={() => this.handleDeleteHotel(edge!.node!.id)}
                                        />
                                    ]}
                                >
                                    <Card.Meta
                                        title={edge!.node!.title}
                                        description={edge!.node!.body}
                                    />
                                </Card>
                            ))}
                            </div>
                        )}
                </Col>
            </Row>
        );
    }
Tadhg McDonald-Jensen
  • 20,699
  • 5
  • 35
  • 59
mfsmusic
  • 33
  • 1
  • 5
  • 1
    what are you expecting `HotelsQuery.Props` to resolve to? – Tadhg McDonald-Jensen Sep 21 '20 at 20:24
  • @TadhgMcDonald-Jensen I just added the class that it's being passed to to the code in the initial question, if that helps? – mfsmusic Sep 21 '20 at 22:16
  • not really, you say `HotelsQuery` is from `generatedModels` file, does that mean it was auto-generated? What decided the type looks like that because it certainly doesn't look like it would support anything along the lines of how you are trying to use it. – Tadhg McDonald-Jensen Sep 21 '20 at 22:20
  • @TadhgMcDonald-Jensen I used yarn generate to generate the models from my yml file. Since I'm following a tutorial that isn't super recent, I have to assume the way the dependencies are interacting is different than it used to be – mfsmusic Sep 21 '20 at 22:42
  • could you link to the tutorial you are using? It seems highly dependent on specifics in that, I'd rather look at it myself than ask you to hunt down what `yarn generate` is actually doing. – Tadhg McDonald-Jensen Sep 21 '20 at 22:45
  • sure, here's the tutorial (it's a notes app but I'm substituting hotels in mine) https://apirobot.me/posts/django-react-ts-how-to-create-and-consume-graphql-api – mfsmusic Sep 21 '20 at 22:50
  • 1
    `HotelsQuery ` is a namespace in the tutorial code, not a type so that explains the syntax for getting `Props` which is correct and the error since you are defining it as a type. The source of your problem is that `HotelsQuery` is incorrectly defined. It should be a namespace with a Props property which is a generic type definition. I'm also not saying the definition you have for `HotelsQuery` above should be the definition for `Props` in the namespace. I haven't gone through the tutorial. If @TadhgMcDonald-Jensen is going through the tutorial they'll be able to provide more details. – MacD Sep 21 '20 at 23:03

1 Answers1

-1

So I took a stab at the tutorial and wanted to explain how a few parts are working.

First off I only did the front end part so when it came time to running yarn gql-gen I hit a block since the codegen.yml references the backend server for getting the types (I assume?)

overwrite: true
schema: "<http://localhost:8000/graphql/>"
documents: "src/**/*.ts"
generates:
    ./src/generatedModels.tsx:
        config: {}
        plugins:
            - "typescript-common"
            - "typescript-client"
            - "typescript-react-apollo"

Here schema is referring to localhost, so I think you need to have the backend configured correctly to expose the types at /graphql/ directory. I just got an error saying I had no sources so either that didn't happen for you because you had the backend setup or you found another work around that might have been incorrect.

user@computer simplenote % yarn gql-gen --config codegen.yml
yarn run v1.22.5
$ /.../simplenote/node_modules/.bin/gql-gen --config codegen.yml
/.../simplenote/node_modules/graphql/jsutils/devAssert.js:12
    throw new Error(message);
    ^

Error: Must provide Source. Received: undefined.

I do want to point out that the path node_modules/.bin/gql-gen indicates what it is actually using, that is a link to node_modules/graphql-code-generator/__/cli.js so the library you are actually using with the yarn gpl-gen is graphql code generator so the documentation on their site may be of help.

So some options for a way forward I would recommend:

  1. look at the config options in the graphql TypeScript React Apollo docs, there may be default options that have changed since the tutorial was written, in particular hooks are replacing HOCs a lot so it's possible the defaults being different is because of that.
  2. re-check that the backend part is running when you run yarn gql-gen and that if you go to http://localhost:8000/graphql/ in your browser I'd expect some kind of data dump, otherwise the codegen.yml may be unable to get the info it needs to generate relevant type definitions.
  3. abandon using HOCs and move to using hooks, the rest of the tutorial will still probably work you just have a function component instead of a class and use probably useHotels from the code generated. I do highly recommend using hooks, there is a good reason they so rapidly replaced HOCs.

I hope one or both of these leads you in enough of a right direction to figure out how to proceed, happy hunting :)

Tadhg McDonald-Jensen
  • 20,699
  • 5
  • 35
  • 59