Reputation: 8128
Currently I have the following component
SearchButton.tsx
export interface Props {
// some other props
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
}
export const SearchButton: React.SFC<Props> = ({
// other props
onClick,
})
Popover.tsx
interface ButtonComponentProps {
onClick: (event: React.MouseEvent<HTMLButtonElement>) => void;
}
interface Props {
buttonComponent: React.ComponentType<ButtonComponentProps>;
}
class FilterPopover extends React.Component<Props, State> {
render() {
const {buttonComponent: BtnComponent} = this.props;
return (
<div>
//...
<BtnComponent onClick={this.open} />
</div>
)
}
}
Page.tsx
<Popover buttonComponent={SearchButton}/>
But I have a mistmatch between types:
The expected type comes from property 'buttonComponent' which is declared here on type 'IntrinsicAttributes & IntrinsicClassAttributes<Popover> & Readonly<{ children?: ReactNode; }> & Readonly<Props>'
So if I change the props from Popover.tsx
interface ButtonComponentProps {
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
}
then interfaces match, but how Typescript is inferring this type through SearchButton
? Is it ok to match interfaces in that way? Why those ones should be the same?
React 16.4.1 Typescript 3.0.1
Upvotes: 2
Views: 10502
Reputation: 30999
TypeScript is comparing the type of SearchButton
, which is React.SFC</*SearchButton*/ Props>
, to the type of the buttonComponent
prop of FilterPopover
, which is React.ComponentType<ButtonComponentProps>
. Looking at the definition of React.ComponentType<P>
, one alternative is React.StatelessComponent<P>
, which is another name for React.SFC<P>
. React.SFC<P>
is invariant in P
, meaning that the types substituted for P
(SearchButton
Props
and ButtonComponentProps
) must match exactly.
You might think a component that accepts an optional prop onClick
should be usable in place of a component that accepts a required prop, because it just means that the optional property will always be set. However, this isn't the case because of the way the optional propTypes
and defaultProps
fields of a stateless component have been declared. I'm not familiar with the detailed rationale behind the design of the type declarations. The easiest thing would be to just match your props interfaces exactly.
Upvotes: 1