J. Reku
J. Reku

Reputation: 529

TypeScript React.SFC has unassignable types?

I'm new to TypeScript and failed to make the errors go away. Tried a lot of things and assign any to wherever I can but I'm still getting the following errors:

(9,7): Type '(props: IRendererProps & { children?: ReactNode; }) => any[]' is not assignable to type 'StatelessComponent<IRendererProps>'.
  Type 'any[]' is not assignable to type 'ReactElement<any> | null'.
    Type 'any[]' is not assignable to type 'ReactElement<any>'.
      Property 'type' is missing in type 'any[]'

This is how I render the component.

<Renderer
  renderStart={0}
  renderEnd={2}
  renderWrapper={(child: any) => <h1>{child}</h1>}
>
  <p>one</p>
  <p>two</p>
  <p>three</p>
</Renderer>

And this is how the component looks like:

import * as React from "react";

interface IRendererProps {
  readonly renderStart: number;
  readonly renderEnd: number;
  readonly renderWrapper: (x: any) => any;
}

const Renderer: React.SFC<IRendererProps> = props => {
  const { children, renderStart, renderEnd, renderWrapper } = props;
  return React.Children.map(children, (child, index) => {
    if (index < renderStart || index > renderEnd) {
      return null;
    } else {
      return renderWrapper(child);
    }
  });
};

export default Renderer;

Does anyone know how to fix these errors?

EDIT: okay, I wrapped React.Children.map in fragments and that fixed it.

return <React.Fragment> {...array.map here...}</React.Fragment>

Upvotes: 0

Views: 374

Answers (2)

Thai Duong Tran
Thai Duong Tran

Reputation: 2522

Basically, in React, one component, regardless it is SFC or a class component, can only return one root node. The definition of the React.StatelessComponent is kind of a hint for you about this.

interface StatelessComponent<P> {
   (props: P & { children?: ReactNode }, context?: any): ReactElement<any> | null
}

Therefore, which your component, wrap the React.Children.map inside a single React.Element will resolve the problem, it can be either a div, a Fragment or whatever you prefer.

Below is an example of how to resolve your problem:

const Renderer: React.SFC<IRendererProps> = props => {
  const { children, renderStart, renderEnd, renderWrapper } = props;

  return (
    <div>
      {React.Children.map(children, (child, index) => {
        if (index < renderStart || index > renderEnd) {
          return null;
        } else {
          return renderWrapper(child);
        }
      })}
    </div>
  );
};

Upvotes: 3

Cerberus
Cerberus

Reputation: 10218

You can't return several elements at once directly. Just wrap them into React.Fragment:

const Renderer: React.SFC<IRendererProps> = props => {
    const { children, renderStart, renderEnd, renderWrapper } = props;
    return <React.Fragment>
        {
            React.Children.map(children, (child, index) => {
                if (index < renderStart || index > renderEnd) {
                    return null;
                } else {
                    return renderWrapper(child);
                }
            })
        }
        </React.Fragment>;
};

Upvotes: 0

Related Questions