Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Define non-arrow React functional component for TypeScript?

You can define a React functional component's types in TypeScript with this:

export const Component: React.FC = () => {
  return // Stuff
};

How do you do the same for a non-arrow function?

function Component() {
  return // Stuff
}

Is there any practice difference? This popular cheat sheet doesn't cover it so I'm wondering if there's a reason not to use that syntax?

https://github.com/typescript-cheatsheets/react-typescript-cheatsheet

like image 704
Evanss Avatar asked Sep 10 '19 18:09

Evanss


3 Answers

If you want to use the full type of a function to type a non-arrow function, you can use something like this (typescript documentation) :

let myAdd: (x: number, y: number) => number =
    function(x: number, y: number): number { return x + y; };

In your case:

const MyComponent: React.FC = function() {
  return <div></div>;
};
like image 109
Jean-Baptiste Rudant Avatar answered Nov 16 '22 04:11

Jean-Baptiste Rudant


How do you do the same for a non-arrow function?

import * as React from 'react';

function NonFatArrow(): React.ReactElement {
    return (
      <>
        Non-fat-arrow function
      </>
    );
}

const FatArrow: React.FunctionComponent = _props => {
  return (
    <section>
      <NonFatArrow/>
    </section>
  );
};

Is there any practice difference?

Stepping aside from React and Typescript, in ES6 a fat arrow function captures few things including this and will carry the capture along self. So if there are thousands of such functions then there will be overhead of captures.

Coming back to React and Typescript, this is not used in React.FunctionComponent(s) however if Typescript transpiler of your choosing transpiles to ES6 then there will be fat arrow functions with captures.

So it all depends on the chosen transpiler and its settings. With Typescript compiler, if you have "target": "es5" in tsconfig.json, then the FatArrow component will be transpiled into ES5 function. Changing the setting to "target": "es6" ensures FatArrow is transpiled to an arrow function. With Babel as transpiler your mileage may vary.

like image 45
winwiz1 Avatar answered Nov 16 '22 03:11

winwiz1


There is better type support for some certain cases when you declare component with const. To understand these cases you can have a look at the React.FC type:

type FC<P = {}> = FunctionComponent<P>;
interface FunctionComponent<P = {}> {
    (props: PropsWithChildren<P>, context?: any): ReactElement | null;
    propTypes?: WeakValidationMap<P>;
    contextTypes?: ValidationMap<any>;
    defaultProps?: Partial<P>;
    displayName?: string;

}

Since react component (even function component) is a bit more than just a plain function - specifying precise type for component itself gives you better type inference:


function FooAsFunc({ children }) { // children has 'any' type
  return 1234
}

const FooAsConst: React.FC = ({ children }) => {
  return 1234 // type error: typescript knows that 1234 is not valid react component return type
}

FooAsFunc.displayName = new Date()
FooAsConst.displayName = new Date() // type error: 'displayName' suppose to be of a type string

In the end, same type safety can be achieved with function declaration as well, but it just requires more code.

like image 26
Serhii Ohorodnyk Avatar answered Nov 16 '22 02:11

Serhii Ohorodnyk