React render props pattern class errors

Multi tool use
React render props pattern class errors
Help please.
it is assumed that the component can be used like this:
<MouseCoordinates></MouseCoordinates>
or
<MouseCoordinates>
{(x,y) => { ... }}
</MouseCoordinates>
I don't understand what does it want.
Here is the code:
import React, { MouseEvent } from 'react';
const initialState = { x: 0, y: 0 };
const defaultProps = {
children: (args: TMouseCoordinates) => null,
};
type TMouseCoordinates = typeof initialState;
type TDefaultProps = typeof defaultProps;
type TState = Readonly<TMouseCoordinates>;
type TProps = Partial<
{
children?: (coordinates: TMouseCoordinates) => JSX.Element;
} & TDefaultProps
>;
class MouseCoordinates extends React.Component<TProps, TState> {
static readonly defaultProps: TProps = defaultProps;
^^^^^^^^^^^^
readonly state: TMouseCoordinates = initialState;
componentDidMount() {
document.addEventListener('mousemove', this.handleMouseMove);
^^^^^^^^^^^^^^^^^^^^
}
componentWillUnmount() {
document.removeEventListener('mousemove', this.handleMouseMove);
^^^^^^^^^^^^^^^^^^^^
}
handleMouseMove = (event: MouseEvent<HTMLElement>): void => {
const { screenX = 0, screenY = 0 } = event;
this.setState(() => ({
x: screenX,
y: screenY,
}));
};
render() {
const { children } = this.props;
const isRenderIsFunction = typeof this.props.children === 'function';
return isRenderIsFunction ? children(this.state) : null;
^^^^^^^^^^^^^^^^^^^^
}
}
I have strange errors at:
static readonly defaultProps: TProps = defaultProps;
Type '{ children: (args: { x: number; y: number; }) => null; }' is not
assignable to type 'Partial<{ children?: ((coordinates: { x: number;
y: number; }) => Element) | undefined; } & { chi...'. Types of
property 'children' are incompatible.
Type '(args: { x: number; y: number; }) => null' is not assignable to type '(((coordinates: { x: number; y: number; }) => Element) &
((args: { x: number; y: number; }) => nu...'.
Type '(args: { x: number; y: number; }) => null' is not assignable to type '((coordinates: { x: number; y: number; }) =>
Element) & ((args: { x: number; y: number; }) => null)'.
Type '(args: { x: number; y: number; }) => null' is not assignable to type '(coordinates: { x: number; y: number; }) =>
Element'.
Type 'null' is not assignable to type 'Element'.
here is cryptic error at:
document.addEventListener('mousemove', this.handleMouseMove);
"Argument of type '(event: MouseEvent) => void' is not
assignable to parameter of type
'EventListenerOrEventListenerObject'.n Type '(event:
MouseEvent) => void' is not assignable to type
'EventListenerObject'.n Property 'handleEvent' is missing in type
'(event: MouseEvent) => void'.",
and last
return isRenderIsFunction ? children(this.state) : null;
Cannot invoke an object which is possibly 'undefined'.
in
defaultProps
you have children
as function returning null
. In TProps
you declare that children
, if present, must also be a function that returns JSX.Element
. But in reality it can't be both - that's what the first error is about.– artem
Jul 1 at 15:44
defaultProps
children
null
TProps
children
JSX.Element
@artem but React.Element - it's a subset that includes null
– Vadim
Jul 1 at 15:47
The third error tells me that you are compiling with
strictNullChecks
turned on, if so then null
as well as undefined
values are excluded from every type.– artem
Jul 1 at 16:01
strictNullChecks
null
undefined
3 Answers
3
type TProps = Partial<
{
children?: (coordinates: TMouseCoordinates) => JSX.Element;
} & {
children: (args: TMouseCoordinates) => null,
}>;
so you simple say: children
props is required and not and contain both functions: (args: TMouseCoordinates) => null
and (coordinates: TMouseCoordinates) => JSX.Element
its simple has no sense.
children
(args: TMouseCoordinates) => null
(coordinates: TMouseCoordinates) => JSX.Element
i guess this is the interface you need:
interface Props{
children?: (args: TMouseCoordinates) => (JSX.Element | null)
}
but I use to declare default props as it has been decsribed in doc
– Vadim
Jul 1 at 15:50
I'm not a novice in typing - I used Flow, but typescript's dances at default props is a little bit confusing
– Vadim
Jul 1 at 15:54
as described in docs default props should be declared in interface as optional and in defaultProps type it should be declared as required If developer does not describe children in the component - component should not do anything -> render null. But if children function is present - it should produce JSX.Element In general - it's an option
– Vadim
Jul 1 at 16:21
I want to have children function optional, but have defaultProps.children to be present in case developer does not describe children function
– Vadim
Jul 1 at 16:29
so, how to in this case should I describe optional children prop?
– Vadim
Jul 1 at 16:37
MouseEvent
should not be imported from React
MouseEvent
Here is the correct code:
import React from 'react';
export type TMouseEventRenderer = (coordinates: ICoordinates) => JSX.Element | null;
const initialState = { x: 0, y: 0 };
const defaultProps = {
children: (() => null) as TMouseEventRenderer,
};
type TDefaultProps = typeof defaultProps;
type TProps = Readonly<{ children?: TMouseEventRenderer } & TDefaultProps>;
type TState = Readonly<ICoordinates>;
class MouseCoordinates extends React.Component<TProps, TState> {
static readonly defaultProps: TDefaultProps = defaultProps;
readonly state: TState = initialState;
componentDidMount() {
document.addEventListener('mousemove', this.handleMouseMove);
}
componentWillUnmount() {
document.removeEventListener('mousemove', this.handleMouseMove);
}
handleMouseMove = (event: MouseEvent): void => {
const { screenX = 0, screenY = 0 } = event;
window.requestAnimationFrame(() => {
this.setState(() => ({
x: screenX,
y: screenY,
}));
});
};
render() {
const { children } = this.props;
const isRenderIsFunction = typeof this.props.children === 'function';
return isRenderIsFunction ? children(this.state) : null;
}
}
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
What were you trying to do? What did you expect? Is this your own code or just code you've picked up from somewhere and tried to use (i.e. why is there code with ~3 independent errors in code you're writing)? Also, try to fix the title. everyone here is seeking help and tech belongs in the tags.
– Damien_The_Unbeliever
Jul 1 at 15:40