typescript - v3.9.7
I have a HOC that pass additional props to the component:
import React from 'react';
interface IWithOwner {
owner: string;
}
type IWithoutOwner<T extends IWithOwner> = Omit<T, keyof IWithOwner> & {owner?: never};
// CORRECT
export function withOwnerOne<TProps extends IWithOwner>(Component: React.ComponentType<TProps>) {
const ComponentWithOwner: React.FunctionComponent<IWithoutOwner<TProps>> = (props) => {
return (
<Component
owner="Tom"
{...props}
/>
);
}
return ComponentWithOwner;
}
// ERROR
export function withOwnerTwo<TProps extends IWithOwner>(Component: React.ComponentType<TProps>) {
return class extends React.Component<IWithoutOwner<TProps>> {
render() {
return (
// '{ owner: string; } & Readonly<IWithoutOwner<TProps>> & Readonly<{ children?: ReactNode; }>'
// is assignable to the constraint of type 'TProps', but 'TProps' could be
// instantiated with a different subtype of constraint 'IWithOwner'.
<Component
owner="Tom"
{...this.props}
/>
)
}
}
}
withOwnerOne
that uses Function component works correctly. While withOwnerTwo
that uses class component has an error. Why do they work differently?
I believe the problem is in props
type.
In first example, FunctionComponent
, type of props
is: IWithoutOwner<TProps> & { children?: ReactNode };
interface IWithOwner {
owner: string;
}
type IWithoutOwner<T extends IWithOwner> = Omit<T, keyof IWithOwner> & {
owner?: never;
};
function withOwnerTwo<TProps extends IWithOwner>(
Component: React.ComponentType<TProps>
) {
const ComponentWithOwner: React.FunctionComponent<IWithoutOwner<TProps>> = (
props
) => {
// React.PropsWithChildren<IWithoutOwner<TProps>> --> IWithoutOwner<TProps> & { children?: ReactNode };
const x = props;
return <Component owner="Dmitry" {...props} />;
};
return ComponentWithOwner;
}
In second, props
has a bit different type:
Readonly<IWithoutOwner<TProps>> & Readonly<{children?: React.ReactNode;}>
function withOwnerOne<TProps extends IWithOwner>(
Component: React.ComponentType<TProps>
) {
class Wrapper extends React.Component<IWithoutOwner<TProps>> {
render() {
//Readonly<IWithoutOwner<TProps>> & Readonly<{children?: React.ReactNode;}>
const props = this.props;
return <Component owner="Dmitry" {...props} />;
}
}
return Wrapper;
}
Now, you may think that the problem is in Readonly
modifier. Readonly
does not cause the error. I strongly believe, that error is caused by contravariance.
Because type of props
is taken from component context, and props generic is placed in differen positions in above components.
I'm open to criticizm, so feel free to point my mistakes.
Covariance/variance/invariance - are too complicated topic for me, I more feel it than understand. So, I will be happy if you point me the correct way.
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.