Search code examples
reactjstypescriptfunctionreact-props

To use React FC on functions


I want to learn how to use React.FC<> in normal functions on react.js.

I know there are two type of functions; the first is (the one that I prefer):

  function Welcome(props) {
      return <h1>Hello, {props.name}</h1>;
    }

The other one is something like this:

const useStyles = makeStyles((theme: Theme) =>
  createStyles({
    root: {
      "& > * + *": {
        marginLeft: theme.spacing(2),
      },
    },
  })
);

I have been told that if I want to use React.FC<> on functions I should do it like this :

const QuestionCard: React.FC<Props>  = () => (
     <div>Question Card</div>
);

export default QuestionCard;

But I don't want to do it with const functions (if that is how it's called). I want to do it with the normal function. I have tried it like this:

export default function QuestionCard : React.FC<Props>() {

  //duda
  return <div>Question Card</div>;
}

But the code editor shows me an error like this: error image


Solution

  • In typescript you can't apply a type alias to a function statement. You are limited to typing the arguments and return type separately.

    function foo(arg1: Arg1Type, arg2: Arg2Type): MyReturnType {
      //...
    }
    

    But if you have a function type alias, you must use this form instead:

    type MyFn = (arg1: Arg1Type, arg2: Arg2Type) => MyReturnType
    const foo: MyFn = (arg1, arg2) => {
      //...
    }
    

    That's just the way to the syntax works. What all that means is that if you want to use the React.FC<Props> type alias for your functional component, then you must use the const MyComponent: React.FC<Props>


    However, (Warning: this drifts into opinion from here on) I want to add that you don't really need the React.FC at all. All it really gives you an extra children?: React.ReactNode prop, which don't want on every component anyway. In fact, if a component does not allow children, and you pass some to it anyway, then I would expect a type error. React.FC doesn't make it easy to be explicit about that.

    For example:

    interface Props {
      foo: string
    }
    
    // A React.FC declared component that should not take children.
    const MyComponentC: React.FC<Props> = ({ foo }) => {
      return <>{ foo }</>
    }
    const c = <MyComponentC foo='bar' /> // expected usage
    const cWithChildren = <MyComponentC foo='bar'>some children</MyComponentC> // no type error
    

    That component is not explicitly typed to accept children, and yet it does. It would be nice if there was a type error.

    Instead, lets look at two examples that don't use React.FC and instead declare children explicity.

    // A function statement declared component that takes no children.
    function MyComponentA({ foo }: Props) {
      return <>Foo: {foo}</>
    }
    const a = <MyComponentA foo='bar' />
    const aWithChildren = <MyComponentA foo='bar'>some children</MyComponentA> // type error
    
    
    // A function statement declared component that DOES take children.
    function MyComponentB({ foo, children }: PropsWithChildren) {
      return <>
        <p>Foo: {foo}</p>
        <p>{children}</p>
      </>
    }
    const b = <MyComponentB foo='bar' /> // type error
    const bWithChildren = <MyComponentB foo='bar'>some children</MyComponentB>
    

    Now the presence of children is enforced by the type system, and the syntax for declaring the component is clean and simple in all cases.

    For these reasons, I wouldn't really recommend using React.FC these days.

    Typescript playground with above example