Search code examples
typescriptarrow-functions

Why does this arrow function not the same as the non-arrow function with the same signature?


I have two functions with the same signature(supposedly), but it seems they are not the same from the compiler's view: the todos in the arrow function is of Todo[] type, while the todos in the NON-arrow function is of any type.

I must be missing something here.

    interface TodoState {
      todos: Todo[]
    }

//no error
    const arrowFunc: React.FC<TodoState> = ({ todos }) => { }

//error: binding element 'todos' implicitly has an 'any' type.ts(7031)
    function nonArrow({ todos }): React.FC<TodoState> {}

enter image description here


Solution

  • const arrowFunc: React.FC<TodoState> = ({ todos }) => {}
    //               ^ function type       ^ props        ^ function return value
    

    This declares a function, and the type of that function conforms to React.FC<TodoState>. Which is to say the functional component accepts props like TodoState, plus a children property and returns JSX.

    function nonArrow({ todos }): React.FC<TodoState> {}
    //                            ^ function return value
    

    But this says something different. nonArrow is a function that does not return JSX, it returns a functional component.

    The first form types the function as React.FC<TodoState>, and the second form types the return value of the function as React.FC<TodoState>.


    There is no syntax to assign an existing function type with the function keyword. Typically if you want a functional component to be typed as such, you use the first form.

    But that's only helpful if you need children as a prop. Otherwise, this simple construct works great for most functional components:

    function MyFuncComp({ propName }: Props) {
      return <h1>{propName}</h1>
    }
    
    // called like this:
    <MyFuncComp propName='foo'/>
    

    All you need to type most of the time is the props, and then just return some JSX and Typescript+React figure the rest out for you.


    Or if your component takes children, it's common to do:

    interface Props {
      propName: string
    }
    
    const MyFuncComp: React.FC<Props> = ({ propName, children }) => {
      return <div>
        <h1>{propName}</h1>
        {children}
      </div>
    }
    
    // called like this:
    <MyFuncComp propName='foo'>
      <p>some children</p>
    </MyFuncComp>