Exploring the integration of React.Components with apollo-client and TypeScript

I am in the process of creating a basic React component using apollo-client alongside TypeScript.

This particular component is responsible for fetching a list of articles and displaying them. Here's the code:

import * as React from 'react';
import graphql from "react-apollo/graphql";
import { ARTICLES_FEED } from "../schemas/queries";
import { Article, ArticlesFeedResponse } from "../schemas/results";
import { ChildProps } from "react-apollo/types";

const AppQL = graphql<ArticlesFeedResponse, {}>(ARTICLES_FEED);

class App extends React.Component<ChildProps<{}, ArticlesFeedResponse>, {}> {
    render() {
        const { loading, feed, error } = this.props.data;

        if (loading) return <div>loading</div>;
        if (error) return <div>{ error }</div>;
        return (
            <React.Fragment>
                <h1>It works!</h1>
                {this.props.data && feed.map( (article:Article) => (
                    <div>{article.shortText}</div>
                ))}
            </React.Fragment>
        );
    }
}

export default AppQL(App);

schemas/results:

export interface Article {
    id: string,
    shortText: string,
    publicationDate: string
}

export type ArticlesFeedResponse = {
  feed: Article[];
}

schemas/queries:

import gql from 'graphql-tag'

export const ARTICLES_FEED = gql`
    query ArticlesFeed {
        feed {
            id
            shortText
            publicationDate
        }
    }
`;

Despite matching signatures, I encountered an error:

Type '(QueryProps<OperationVariables> & Partial<ArticlesFeedResponse>) | undefined' has no property 'loading' and no string index signature.

I seem to be confused - the imported types are:

ChildProps:

export declare type ChildProps<P, R> = P & {
    data?: QueryProps & Partial<R>;
    mutate?: MutationFunc<R>;
};

QueryProps:

export interface QueryProps<TVariables = OperationVariables> {
    error?: ApolloError;
    networkStatus: number;
    loading: boolean;
    variables: TVariables;
    fetchMore: (fetchMoreOptions: FetchMoreQueryOptions & FetchMoreOptions) => Promise<ApolloQueryResult<any>>;
    refetch: (variables?: TVariables) => Promise<ApolloQueryResult<any>>;
    startPolling: (pollInterval: number) => void;
    stopPolling: () => void;
    subscribeToMore: (options: SubscribeToMoreOptions) => () => void;
    updateQuery: (mapFn: (previousQueryResult: any, options: UpdateQueryOptions) => any) => void;
}

Therefore, ChildProps should include both the loading and error properties. The inclusion of | undefined in the union remains puzzling to me.

Any tips or advice?

P. S. When I refrain from importing the default ChildProps from react-apollo/types, and opt for this modified version instead:

type ChildProps<P, R> = P & {
    data: QueryProps & R;
    mutate?: MutationFunc<R>;
};

The code operates smoothly. I am left wondering - did I make a mistake, or could this be a bug within the react-apollo/types package?

Answer №1

The graphql type annotation specifies that it takes

<ParentProps, QueryResponse, Variables>
. In this case, what is being passed is:

graphql<ArticlesFeedResponse, {}>(ARTICLES_FEED)

It should actually be passed like this:

graphql<{} ArticlesFeedResponse>(ARTICLES_FEED)

Additionally, the ChildProps annotation indicates that data can possibly be undefined. Making adjustments for this will ensure proper type checking.

class App extends React.Component<ChildProps<{}, ArticlesFeedResponse>, {}> {
  render() {
    if (!this.props.data) {
      return;
    }

    const { loading, feed, error } = this.props.data;

    if (loading) return <div>loading </div>;
    if (error) return <div>{error} </div>;

    return (
      <React.Fragment>
      <h1>It works!</h1>
        {
          feed && feed.map((article: Article) => (
            <div>{ article.shortText } </div>
          ))
        }
      </React.Fragment>
    );
  }
}

An alternative approach is to specify

const { loading, feed, error } = this.props.data!;
to inform the type checker that it won't be undefined. Typically, the data prop should never be undefined, so marking it as present with this.props.data! is considered safe. It's also possible that the ChildProps annotation might be incorrect or a bug. Notably, the example docs do not pass typechecking.

This code has been tested against

<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="2f5d4a4e4c5b024e5f404343406f1d011e0116">[email protected]</a>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips on transitioning a Node.js application from JavaScript to TypeScript incrementally

I have a JavaScript node application that has grown quite large and I am considering migrating to TypeScript for faster development and easier code maintenance. I have installed TypeScript along with the node and mocha types using the following commands: ...

How can you store form field validation rules (for example, firstname.dirty) in an array within TypeScript in Angular?

How do I save form field validation rules in an array? What should replace /'''''HERE'''''/ with? formfields: Array<Object> = [ {label: "Employer:", control: "employer", val ...

Tips for retrieving an item from a (dropdown) menu in Angular

I am facing an issue with selecting objects from a dropdown list. The array called "devices" stores a list of Bluetooth devices. Here is the HTML code: <select (change)="selectDevice($event.target.data)"> <option>Select ...

Create a .d.ts file for a custom JavaScript file

I am working on an application written in JavaScript and considering incorporating TypeScript for a new feature. Currently, I have a base class defined in JavaScript as shown below: // base.js module.exports = function BaseClass () { // ... ... }; M ...

Encountering error "module fibers/future not found" while creating a meteor method in typescript

While working on a Meteor method for async function in my project that combines Meteor with Angular2 using Typescript ES6, I encountered an error. The issue is related to a sync problem in the insert query when inserting data with the same name. To resolve ...

The error message "better-sqlite3 TypeError: o.default is not a constructor" indicates that

As part of my vscode extension development in typescript, webpack, and better-sqlite3, I am attempting to create a database within the C:\Users\userName\AppData\Roaming\Code\User\globalStorage\ folder. However, when ...

Unlocking Column Data Tooltips in Angular Datatables: A Step-by-Step Guide

I have a single datatable and was wondering how to implement tooltips for when hovering over table cells. I tried the following code snippet, which successfully populated the tooltips. However, I am interested in achieving the same functionality using Angu ...

Is it possible to expand or merge Nestjs decorators?

My custom decorator named "User" is quite simple: export const User: () => ParameterDecorator = createParamDecorator( (data: any, req): UserIdentity => { const user = getUser(req); return user; }, ); Now, I'm in need of validating ...

Node_modules folder is excluded from Typescript compilation

I am struggling to understand why TypeScript is not compiling code from the node_modules folder. Below is the content of my tsconfig.json file: { "compilerOptions": { "rootDir": ".", "baseUrl": ".", "paths": { "shared": ["./src/shared ...

Tips for obtaining the accurate HTML code format using Angular 2's input feature:

I am looking to retrieve all the code with an input as [input] and a tag as #tag. When attempting to obtain HTML code with jQuery using console.log($("#content")[0].outerHTML);, this is an example of how the code looks: <div dnd-droppable [dropZones]= ...

retrieve the state property from NavLink

I am encountering an issue with passing objects through components in my project. Specifically, I have a chat object within a component that defines a NavLink. When a user clicks on the ChatsElement, which is a link, the page navigates to the URL /friends/ ...

Combining Firebase analytics with an Ionic 3 application using the Ionic Native plugin

I placed the GoogleService-Info.plist file at the root of the app folder, not in the platforms/ios/ directory. When I tried to build the app in Xcode, an error occurred in the following file: FirebaseAnalyticsPlugin.m: [FIROptions defaultOptions].deepLin ...

"Encountering Devextreme Reactive Errors while navigating on the main client

Attempting to integrate Devextreme with Material Ui in my Typescript React app has been a challenge. Despite following the steps outlined in this documentation and installing all necessary packages, I am encountering issues. I have also installed Material ...

Issue with react-native-svg ForeignObject missing in project (React Native with Expo using TypeScript)

I am working on a React Native project in Expo and have incorporated the expo TypeScript configuration. Using "expo install," I added react-native-svg version 9.13.3 to my project. However, every time I attempt to render the SVG using react-native-svg, I ...

What is the best way to retrieve class members using component properties?

I am looking to implement a mixin for setting the header and meta data in my project. I recently discovered vue-meta, which seems to work really well for this purpose. However, I am still getting acquainted with TypeScript and class-based components. How ...

Tips on retrieving enum values in typescript

Having trouble retrieving values from an enum? Check out this snippet of code: export const enum ComplianceType { ENGINEER_ASSESMENT = 'ENGINEER_ASSESMENT', CONSTRUCTION_COMPLIANCE = 'CONSTRUCTION_COMPLIANCE', ARCHITECTURE_ASSIGN ...

Error in Typescript: Array containing numbers is missing index property `0`

This is the code for my class: class Point{ coordinates: [number, number, number]; constructor(coordinates: [string, string, string]) { this.coordinates = coordinates.map((coordinate) => { return Math.round(parseFloat(coordinate) *100)/ ...

Experiencing the issue of receiving unexpected commas following a div

Here is the code written in TypeScript for creating an HTML table that displays items from nested objects. The code is functional, but there seems to be an issue with extra commas being printed which are not part of any specific line being executed. im ...

Is it necessary to sanitize input fields manually in Angular 6?

Is it necessary for me to manually sanitize all user inputs, or does Angular handle this process automatically? In my login form, the data is sent to the server upon submission. Do I need to explicitly sanitize the data, or does Angular take care of sanit ...

Tips for retrieving a nested data value within an array

I am currently puzzled by the undefined error I encounter when attempting to access a value using dot notation. The following illustrates my point: My goal is to retrieve the value from within the nested object in the headline color array: ...