I have a function, which takes two params: a react component, and a string. I am trying to give them correct typings, however, am confused as to why the following wont work...
The problem is with the typing with GivenComponent in the Function. By giving the param that specific typing of Component<>, the return of the GivenComponent (within the < Query />) errors stating the following:
JSX element type 'GivenComponent' does not have any construct or call signatures. [2604]
However, how would you type that correctly? That param is a React Component, could be both a functional or a class component. As seen in the second part of code, the param isn't given as < MyComponent />, it is given as MyComponent - so not the "rendered" jsx? maybe that changes things
Basically takes a component and returns it with a higher order component wrapper around it
import React, { Component } from "react";
const withQueryData: Function = (
GivenComponent: Component<{ data: {} }, any>,
query: string
) => () => (
<Query query={gql(query)}>
{({ loading, error, data }) => {
if (loading) return <p>Loading...</p>;
if (error) return <p>Error! {error.message}</p>;
return <GivenComponent data={data} />;
}}
</Query>
);
export default withQueryData;
example of how the function above is called with params
class MyComponent extends Component<...removed...> {
render() {
return (
<div>...</div>
);
}
}
const MyComponentQuery = `query goes here...`;
const MyComponentWithData = withQueryData(
MyComponent,
MyComponentQuery
);
export default MyComponentWithData;
Transforming my comment into an answer.
There are two typings for declared react components:
React.ComponentClass
- a typing for react component that is declared as class:
class SomeComponent extends React.Component {...} // this is React.ComponentClass
React.FunctionComponent
is a typing for function component (CO to the rescue! :D)
const MyFunctionComponent: React.FunctionComponent = props => "something"
So, if your component is one of ComponentClass
or FunctionComponent
, you can use Union Type and tell the TypeScript about it in this way:
const SomeUnionType: React.ComponentClass | React.FunctionComponent
Thats it! Hope, that helps :)
You need to use ComponentType
to represent a component type (functional or class, defined in react definitions as type ComponentType<P = {}> = ComponentClass<P> | FunctionComponent<P>;
).
Also you might want to allow the HOC to forward properties from the wrapped component.
Also remove the Function
annotation from withQueryData
as that will remove all type safety from withQueryData
.
import { Component, ComponentType } from "react";
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
const withQueryData = <P extends { data: {} }>(
GivenComponent: ComponentType<P>,
query: string
) => (p: Omit<P, 'data'>) => (
<Query query={gql(query)}>
{({ loading, error, data }) => {
if (loading) return <p>Loading...</p>;
if (error) return <p>Error! {error.message}</p>;
return <GivenComponent data={data} {...p as any} />;
}}
</Query>
);
class MyComponent extends Component<{ data: {}, otherProp: string }> {
render() {
return (
<div>...</div>
);
}
}
const MyComponentQuery = `query goes here...`;
const MyComponentWithData = withQueryData(
MyComponent,
MyComponentQuery
);
export default MyComponentWithData;
let o = () => <MyComponentWithData otherProp="" ></MyComponentWithData> // otherProp required, data provided bu the HOC
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.