Property 'children' is missing in type

14,601

Solution 1

One possible solution is to leverage the default children mechanism in functional components, React.FC, which lets you mount children without explicitly include them as a prop in your type definition. For your case this is achievable by applying the following changes:

interface Props
  extends BorderProps,
    ColorProps,
    FlexboxProps,
    LayoutProps,
    SpaceProps,
    TypographyProps {
  title: string;
}

const Collapsible: React.FC<Props> = ({ children, title, ...rest }) => {
  ...
};

Working sandbox for this

Solution 2

step 1

add React.FC: it already comes with children declared for you. And add your custom Props inside the React's.

Your code should be this:

const Collapsible : React.FC<Props> = ({ children, title, ...rest }) => {

step 2

interface Props extends BorderProps,
    ColorProps,
    FlexboxProps,
    LayoutProps,
    SpaceProps,
    TypographyProps {
  children: ReactNode; // as React.FC declares it for you, just delete this line
  title: string;
}
Share:
14,601
Erazihel
Author by

Erazihel

I'm a JavaScript developper. I started coding when I was 12 and I still love it, especially using JavaScript over the last 5 years! I work on projects of my own on my free time. I also love skateboarding and snowboarding (even if it's hard to snowboard in Paris..)

Updated on July 28, 2022

Comments

  • Erazihel
    Erazihel almost 2 years

    I am trying to setup Storybook with Typescript using babel-loader and ts-loader.

    Everything works fine except using children in a React component:

    [tsl] ERROR in .../stories/index.stories.tsx(8,56)
          TS2769: No overload matches this call.
          Property 'children' is missing in type '{ title: string; }' but required in type 'Props'.
    

    This is the .storybook/main.js file:

    module.exports = {
      addons: [
        "@storybook/addon-knobs",
      ],
      stories: ["../packages/**/*.stories.tsx"],
      webpackFinal: async config => {
        config.module.rules.push({
          test: /\.(ts|tsx)$/,
          exclude: /node_modules/,
          use: [
            {
              loader: require.resolve('ts-loader')
            },
            {
              loader: require.resolve('babel-loader'),
              options: {
                presets: [
                  "@babel/preset-env",
                  "@babel/preset-react"
                ]
              }
            }
          ],
        });
    
        config.resolve.extensions.push('.ts', '.tsx');
    
        return config;
      }
    };
    

    This is the index.stories.tsx file:

    import React from "react";
    
    import Collapsible from "../src";
    
    export default {
      title: "Collapsible"
    };
    
    const content = <span>Content</span>;
    
    export const simpleCollapsible = () => (
      <Collapsible title="Collapsible">{content}</Collapsible>
    );
    

    And this is the implementation of Collapsible:

    import React, { ReactNode, useState } from "react";
    import styled, { ThemeProvider } from "styled-components";
    import {
      BorderProps,
      ColorProps,
      FlexboxProps,
      LayoutProps,
      SpaceProps,
      TypographyProps
    } from "styled-system";
    import Theme from "@atw/theme";
    
    import { KeyboardArrowDown } from "@styled-icons/material";
    
    import Box from '~/box';
    import Button from '~/button';
    
    interface Props
      extends BorderProps,
        ColorProps,
        FlexboxProps,
        LayoutProps,
        SpaceProps,
        TypographyProps {
      children: ReactNode;
      title: string;
    }
    
    const Collapsible = ({ children, title, ...rest }: Props) => {
      const [isCollapsed, setIsCollapsed] = useState(false);
    
      const handleCollapse = () => {
        setIsCollapsed(!isCollapsed);
      };
    
      return (
        <ThemeProvider theme={Theme}>
          <Button
            border="none"
            padding={0}
            marginBottom={2}
            width={1}
            textAlign="start"
            onClick={handleCollapse}
            {...rest}
          >
            <IconBox isCollapsed={isCollapsed}>
              <KeyboardArrowDown size="24px" />
            </IconBox>
            {title}
          </Button>
          {!isCollapsed && (
            <Box display="flex" flexDirection="column">
              {children}
            </Box>
          )}
        </ThemeProvider>
      );
    };
    
    export default Collapsible;
    

    Is there anything here I'm doing wrong?