I'm trying to connect a React element with react-redux
that has arbitrary/generic props, but it's not compiling correctly. I've tried using JSXElementConstructor
and (new (props: Props) => React.Component<Props, any>)
instead of ComponentType
, but got a different error about how Props
could be instantiated with a different type. Here's the code. Any help would be appreciated.
https://github.com/piotrwitek/react-redux-typescript-guide/issues/55 looks related, but that seems to be about the props having a generic, instead of the props themselves being a generic.
Code
import React from "react";
import { connect } from "react-redux";
interface StoreState {
someState: number;
}
// Tried `React.JSXElementConstructor<Pros>`
// and `(new (props: Props) => React.Component<Props, any>)`
// instead of `React.ComponentType<Props>`, but got a different error.
function createWrapperComponent<Props>(
componentElement: React.ReactElement<
Props,
React.ComponentType<Props> & { update(props: Props): void }
>
) {
const props = componentElement.props;
const UnconnectedComponent = componentElement.type;
const ConnectedComponent = connect<StoreState, {}, Props, StoreState>(
(state) => state
)(UnconnectedComponent);
return class WrapperComponent extends React.Component<any> {
static update = UnconnectedComponent.update;
render() {
return <ConnectedComponent {...props} />;
}
};
}
Playground Link: Provided
Update: Here's an approach that avoids the initial cast to any
. Now I'm casting the props passed to ConnectedComponent
instead. Investigating the type issue there might reveal whether there are more potential issues than the one I mentioned.
What you're doing is not sound. If Props
were { someState: string }
, your UnconnectedComponent
would be expecting its someState
prop to be a string
, but it would be a number
.
If stateProps
and dispatchProps
should override ownProps
, which is what your code is doing now, I'm not sure whether you're going to be able to get the types to work automatically the way you want. TypeScript can't figure out that the following is sound:
function a<Props>(
b: { [K in keyof Props]: K extends keyof StoreState ? StoreState[K] : Props[K] }
): Omit<Props, keyof StoreState>
{
return b;
}
Maybe you should bite the bullet and use any
. Here's a sample of how you might try to make the caller-facing types safer.
If you instead want ownProps
to override stateProps
, you would want to provide a mergeProps
argument to connect
.
However, be warned that when you create a ReactElement
via JSX, the type
field has type any
, which of course won't give you type safety if you then call createComponent
.
Your Props
doesn't refer to any types defined. So I guess leave it blank is ok?
function createComponent(componentElement: React.ReactElement<{}, React.ComponentType>) {
const props = componentElement.props;
const UnconnectedComponent = componentElement.type;
const ConnectedComponent = connect<StoreState, {}, {}, StoreState>(state => state)(UnconnectedComponent);
return <ConnectedComponent {...props} />
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With