Reputation: 23
const withFirebase = <Props extends {firebase: Firebase}>(
Component: React.ComponentType<Props>
): ComponentType<Omit<Props, "firebase">> => (props) => (
<FirebaseContext.Consumer>
{(firebase) => <Component {...props} firebase={firebase} />}
</FirebaseContext.Consumer>
);
export default withFirebase;
Here
<Component {...props} firebase={firebase} />
Throws the below typescript error
Type 'Pick<Props, Exclude<keyof Props, "firebase">> & { firebase: Firebase | null; children?: ReactNode; }' is not assignable to type 'IntrinsicAttributes & Props & { children?: ReactNode; }'.
Type 'Pick<Props, Exclude<keyof Props, "firebase">> & { firebase: Firebase | null; children?: ReactNode; }' is not assignable to type 'Props'.
'Props' could be instantiated with an arbitrary type which could be unrelated to 'Pick<Props, Exclude<keyof Props, "firebase">> & { firebase: Firebase | null; children?: ReactNode; }
Omit<Props, "firebase"> is added to avoid the required prop error in the Wrapped component import.
like
const App = () => {
return (
<ItemWithFirebase /> // If not omit is available this will throw prop firebase not available error
)
}
const Item: FC<{firebase: Firebase}> = ({firebase}) => {
...
}
const ItemWithFirebase = withFirebase(Item);
I have casted the spread props as below
<Component {...(props as Props)} firebase={firebase} />}
But I am not sure if I am doing it right. Could you please let me know if there are any other way to tackle this error?
Upvotes: 2
Views: 642
Reputation: 42188
This comes up all the time when writing HOCs. You're looking at the error and it says "We take Props
, we remove Props['firebase']
, we add {firebase: Firebase | null}
, and we're not sure if this object is assignable to Props
". You might think, "if I removed firebase
and then added it back, of course that's the same thing". Technically, Props extends {firebase: Firebase}
means that Props['firebase']
could be something more specific than Firebase
, in which case the value that you provide to it wouldn't be sufficient. That weird edge case is one of two reasons that you get an error.
The other reason is that Props
doesn't allow for firebase
to be null
, but the Consumer
says that it could either have Firebase
or null
.
But 99.9% of the time it is the same thing, so it's fine to assert {...(props as Props)}
like you have done here. You might want to expand Props
to allow null
, but if you know that it's not going to be null
in your app then it's not an issue.
You can avoid some of the errors if you let your generic Props
represent the props without firebase
. Instead of dropping firebase
from the return, we add it to the Component
. We Omit
any existing definition of firebase
from Props
which rules out the edge case where the Component
requires some value of firebase
other than what we provide.
const withFirebase = <Props extends {}>(
Component: React.ComponentType<Omit<Props, 'firebase'> & {firebase: Firebase | null}>
): ComponentType<Props> => (props) => (
<FirebaseContext.Consumer>
{(firebase) => <Component {...props} firebase={firebase} />}
</FirebaseContext.Consumer>
);
Upvotes: 1