Using ownProps as a parameter when passing it into a component that has been wrapped by

Update: Added some additional details

Utilizing the Apollo graphql wrapper to wrap a component, I aim to pass the onPaymentLoaded property from OwnProps into the wrapped function. Despite my efforts, the code does not proceed beyond the TypeScript compiler unless I include onPaymentLoaded as part of the Result interface as well. This situation is quite perplexing. My understanding is that the Result delineates what is expected back from the query - which in this case is just Payment. So why does the compiler raise objections when onPaymentLoaded is omitted?

const PAYMENT_QUERY = gql`
    query payment($id: ID!) {
        payment(id: $id) {
            id
            amount
        }
    }
`;

interface Result {
    payment: Payment;
    // ----- If onPaymentLoaded is not included in the Result,
    //       the error mentioned below arises. The issue at hand is puzzling,
    //       since onPaymentLoaded isn't part of the query result!!!
    onPaymentLoaded: (payment: Payment) => void;
}

type WrappedProps = Result & QueryProps;

interface OwnProps {
    paymentid: string;
    onPaymentLoaded: (payment: Payment) => void;
}

const withPayment = graphql<
    Result,
    OwnProps,
    WrappedProps
>(PAYMENT_QUERY, {
    options: ({ paymentid }) => ({
        variables: { id: paymentid }
    }),
    props: ({ data, ownProps }) => ({ ...data, ownProps })
});

export const PaymentContainer = withPayment(
    // ----- Error occurs if onPaymentLoaded is excluded from the Result interface above:
    //       Type 'Response & QueryProps<OperationVariables> &
    //       { children?: ReactNode; }' has no property 'onPaymentLoaded'
    //       and no string index signature."
    ({ loading, error, payment, onPaymentLoaded }) => {
        return (
            <PaymentView
                loading={loading}
                error={error}
                payment={payment}
                onPaymentLoaded={onPaymentLoaded}
            />
        );
    }
);

Answer №1

When dealing with the first error, it's important to remember that shorthand syntax for object properties does not allow dots in notation. In addition, you may not need to transform props at all since your onPaymentLoaded will be passed down anyway.

Another aspect to consider is:

graphql< TResult = {}, TProps = {}, TChildProps = ChildProps<TProps & TResult>

This implies that only TResult and TProps need to be passed as input, while leaving out the third generic parameter.

Furthermore, it is advisable to utilize recompose's compose function, as the graphql enhancer may not be the only one used.

Here is an example that may provide some guidance:

import * as React from 'react';
import { compose } from 'recompose';
import graphql from 'react-apollo/graphql';
import { QueryProps } from 'react-apollo';

import { MenuDishQuery } from '@admin/graphql/types.gen';
import { MenuDish as MenuDishPres } from '@admin/components';
import { dataLoadingOrError } from '@common/utils';

const DATA_QUERY = require('./data.gql');

type OwnProps = {
  recipeId: string;
}

type Data = { data: MenuDishQuery.Query & QueryProps }

type WrappedProps = OwnProps & Data;


export const MenuDish = compose<WrappedProps, OwnProps>(

  graphql<MenuDishQuery.Query, WrappedProps>(DATA_QUERY, {
    options: props => ({
      variables: {
        recipeId: props.recipeId
      }
    })
  }),

  dataLoadingOrError()


)(props => {

  const { data } = props;
  const { recipe } = data;

  return <MenuDishPres
    dish={{ recipe }}
  />


});

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 for setting up a proxy with an enum

I am facing an issue with setting up a Proxy for an enum. Specifically, I have an enum where I want to assign a value to this.status using a Proxy. However, despite my expectations, the output "I have been set" does not appear in the console. Can anyone ex ...

The extensive magnetic scrolling functionality in Ionic 2 sets it apart from other frameworks

Hi everyone, I could really use some assistance! I've been working on developing an Ionic 2 App and my navigation setup is not too complex. I have a main menu where clicking on an item opens another menu with a submenu. From there, if I click on an i ...

Creating a consistent template for typing TypeScript generics

Is it possible to modify a generic function so that it can accept an unlimited number of arguments and concatenate them with .'s? This function should be able to handle nested objects with any number of keys. The current code snippet works when manua ...

Issues arise when Typescript fails to convert an image URL into a base64 encoded string

My current challenge involves converting an image to base 64 format using its URL. This is the method I am currently using: convertToBase64(img) { var canvas = document.createElement("canvas"); canvas.width = img.width; canvas.height = img.he ...

Assign a class to a button created dynamically using Angular

While working on my project, I encountered an issue where the CSS style was not being applied to a button that I created and assigned a class to in the component.ts file. Specifically, the font color of the button was not changing as expected. Here is the ...

In TypeScript, there is a mismatch between the function return type

I am new to TypeScript and trying to follow its recommendations, but I am having trouble understanding this particular issue. https://i.stack.imgur.com/fYQmQ.png After reading the definition of type EffectCallback, which is a function returning void, I t ...

Is there a way to send both a file and JSON data in a single HTTP request?

Once I developed a small application using NestJs where I implemented a BFF (Backend for Frontend) service. Within this service, I tried to execute a POST request to create a new user while also including the user's avatar in the same request. Here is ...

Utilizing React with Typescript to Implement useReducer with Action Interface Featuring Union Type Support

My current challenge involves creating a reducer using the useReducer hook. I have defined an interface named Action which includes a property that can hold either a string or a number: type Actions = 'update_foo' | 'update_bar'; inter ...

What is the purpose of using detectChanges() when utilizing the default change detection strategy in Angular?

Currently, I am facing an issue while working on my Angular 4 application. I have noticed that I need to use this.changeDetectorRef.detectChanges(); to update the view whenever there is a change in the model. This requirement arises in scenarios like pagin ...

The type '{ id: string; }' cannot be assigned to the type 'DeepPartial<T>'

In my code, I am attempting to create a generic function that abstracts my repository infrastructure for creating a where clause. export type DeepPartial<T> = T extends object ? { [P in keyof T]?: DeepPartial<T[P]>; } : T; export int ...

Are there any disadvantages to keeping the selector of routed components in place?

The instructions in the Angular routing documentation - Add heroes functionality mention making some adjustments: Several changes need to be made: -Remove the selector (routed components do not need them). -Remove the <h1>. Is it beneficial to kee ...

Linking key value pairs through a TypeScript interface

coding interface StoreActions { setUserName: string actionOne: string[] actionTwo: { testValue: string } } interface CustomActions extends AnyAction { typeOfAction: keyof StoreActions // additionalData:??? } The attribute typ ...

Angular 7 - Creating tooltips with multiline text

I've utilized template strings to create a multi-line string. toolTip = ` ${Test} : ${number} ${Test} : ${number} ${Test} : ${number} ${Test} : ${number} ${Test} : ${number}}`; The issue I'm facing is that w ...

The error thrown is: "TypeError: device.devices.map is not a valid function

I encountered an error after adding products to the page and I'm having trouble identifying the cause. const {device} = useContext(Context) 91 | </div> > 92 | <div className="inner-display-collection"> | ^ ...

Design buttons that are generated dynamically to match the style

I have a challenge in styling dynamically generated buttons. I've developed a component responsible for generating these dynamic buttons. const TIMER_PRESETS: Record<string, number> = { FIFTHTEENSEC: 15, THIRTYSEC: 30, FORTYFIVESEC: 45, ...

A guide on utilizing Material UI Fade for smoothly fading in a component when a text field is selected

I am facing an issue with a text field input and a helper component. My goal is to have the helper component fade in when a user focuses on the input field. The helper component is wrapped as follows: <Fade in={checked}> <DynamicHelperText lev ...

An issue has occurred: function() is not a valid function

Issue: core.mjs:10132 ERROR TypeError: block.getDepartment is not a function at FirebaseService.mapDatabaseToBlock (firebase.service.ts:54:30) at firebase.service.ts:45:60 at Array.map (<anonymous>) at firebase.service.ts:45:42 at ...

Node.js and Typescript encountering issues resolving module paths

I am brand new to both Express and Typescript. I recently inherited a project that utilizes express for an API. I need to make some modifications, but I am having trouble transpiling the code. I have exhausted all my options and now I'm seeking help h ...

Is it possible to generate a property for an interface by casting a key within a for-in loop?

When I attempt to set a property on an object with a value from a dynamically generated form, I utilize a for-in loop to identify a property in the object and assign it. FormFeatureArray.forEach((el) => { // form handling stuff omitted For(c ...

Merge arrays values with Object.assign function

I have a function that returns an object where the keys are strings and the values are arrays of strings: {"myType1": ["123"]} What I want to do is merge all the results it's returning. For example, if I have: {"myType1": ["123"]} {"myType2": ["45 ...