4

I am starting out with TypeScript on a React app (next.js) and I'm not sure how to type React components.

I have a component like...

type Props = {
  children: JSX.Element;
};

export default function SiteLayout({ children }: Props): React.FC {
return (
  <div>
    {children}
  </div>
)

But this gives me the following error:

var children: JSX.Element
Type 'Element' is not assignable to type 'FC<{}>'.
Type 'Element' provides no match for the signature '(props: { children?: ReactNode; }, context?: any): ReactElement<any, any>'.ts(2322)

I also tried to get it working with simply using JSX.Element:

type Props = {
  children: JSX.Element;
};

export default function SiteLayout({ children }: Props): JSX.Element {

return (
  <div>
    {children}
  </div>
)

But this gives the following error in child components.

(alias) function SiteLayout({ children }: Props): JSX.Element import SiteLayout
This JSX tag's 'children' prop expects a single child of type 'Element', but multiple children were provided.ts(2746)

The above component is being consumed in by a Next.js page component like:

import Head from 'next/head';
import SiteLayout, { siteTitle } from '../../components/SiteLayout';

export default function myPage() {
  const pageTitle = 'My Page';


  return (
    <SiteLayout>
      <Head>
        <title>{siteTitle + ' - ' + pageTitle}</title>
      </Head>
      <div>
        content...
      </div>
    </SiteLayout>
  );
}

What is the correct approach? I'm confused when JSX.Element should be used and when React.FC should be.

5
  • 1
    Can you please share how you are consuming the component? React.FC cannot be the return type. Its variable type. Also the error says about children and not return type Commented Jul 2, 2020 at 6:43
  • Thanks @Rajesh, I update my question. Is this enough info? Commented Jul 2, 2020 at 8:08
  • unfortunately the question is closed and still don't get it. Anyone know of another forum where I can get help on this? A slack channel maybe Commented Jul 2, 2020 at 8:09
  • 1
    children: JSX.Element; means you will have 1 child. You have more than one. Try Array<JSX.Element> Commented Jul 2, 2020 at 8:21
  • Thank you @Rajesh, that answers my question. I also just tried children: JSX.Element | any; but Array<JSX.Element> is better. Thanks Commented Jul 2, 2020 at 8:39

2 Answers 2

7

The return type of the function is not a component, the function itself is component. That's why instead of

function SiteLayout({ children }: Props): React.FC { ...

It should be:

const SiteLayout: React.FC<Props> = ({ children }: Props) => {
    return (
      <div>
        {children}
      </div>
    );
}

Regarding the type of children prop, if there's no restriction on kind of children (string, boolean, element etc,) better to use ReactNode:

type Props = {
    children: React.ReactNode
}

Here's how it is defined.

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks, I got it working with... const SiteLayout: React.FC = ({ children }: Props) => {...}. What is the reason for adding Props also after React.FC?
Also, do you know if it has to be an arrow function assigned to a constant rather than a simple function declaration?
Yes, so you could just go with const SiteLayout: React.FC = ({ children }) => {} for this specific example (because React.FC) already types children with { children?: ReactNode }
If you were adding props other than children - this way they were exposed to consumers of this component
Regarding function vs cont, currently there's no way to properly type functions (there're several workarounds, but I'd suggest to stick with const variant)
|
0

Your function is returning a React.FC type, which shouldnt be the case. The return type of function components is ReactNode, plus children are implicitly provided by the React.FC typing. If you explicitly type them, you can omit the React.FC and write:

const SiteLayout = ({children}: Props) => {
  return (
    <div>
      {children}
    </div>
  )
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.