DEV Community

Cristian Sifuentes
Cristian Sifuentes

Posted on

Stop the Debate: **When to Use `FC<Props>` vs Inferred Arrow Functions in React + TypeScript**

Stop the Debate: **When to Use  raw `FC<Props>` endraw  vs Inferred Arrow Functions in React + TypeScript**

Stop the Debate: When to Use FC<Props> vs Inferred Arrow Functions in React + TypeScript

Turning a two‑line snippet into a masterclass on generics, JSX.Element return types, and bundle hygiene.


TL;DR

Style Snippet Pros Cons
Inferred Arrow export const GifList = ({ gifs }: Props) => … 🧬 TypeScript infers props; slimmer bundle; flexible return type Must annotate return type yourself if you care; no built‑in children
FC<Props> export const GifList: FC<Props> = ({ gifs }) => … Auto‑adds children, propTypes, defaultProps; readable to TS newcomers Adds an extra import + generic; can hide implicit children; historically caused undefined JSX return edge cases

1 The Two Contenders

A. Vanilla Arrow with Inferred Props

interface Gif {
  id: string;
  url: string;
  title: string;
  width: number;
  height: number;
}

interface Props {
  gifs: Gif[];
}

export const GifList = ({ gifs }: Props) => (
  <div className="gifs-container">
    {gifs.map(({ id, url, title, width, height }) => (
      <div key={id} className="gif-card">
        <img src={url} alt={title} />
        <h3>{title}</h3>
        <p>
          {width} × {height} (1.5 MB)
        </p>
      </div>
    ))}
  </div>
);
Enter fullscreen mode Exit fullscreen mode
  • TypeScript infers the return type as JSX.Element because the body is JSX.
  • No implicit children prop — ideal when the component is truly leaf‑only.

B. Explicit Functional Component (FC) Generic

import type { FC } from "react";

export const GifList: FC<Props> = ({ gifs }) => (
  /* same JSX */
);
Enter fullscreen mode Exit fullscreen mode

What FC<Props> really is:

type FC<P = {}> = FunctionComponent<P>;

interface FunctionComponent<P = {}> {
  (props: PropsWithChildren<P>, context?: any): ReactElement | null;
  propTypes?: WeakValidationMap<P>;
  defaultProps?: Partial<P>;
  displayName?: string;
}
Enter fullscreen mode Exit fullscreen mode

Key differences

  1. children auto‑included via PropsWithChildren<P>.
  2. Return type is ReactElement | null — avoids older undefined pitfalls.
  3. Static props (displayName, propTypes) are typed out of the box.

2 Performance & Bundle Size

The extra import type { FC } is erased at compile‑time.

Actual cost: < 0.1 kB gzipped — negligible.

Still, arrow functions keep code minimal when you ship many micro‑components.


3 When to Pick Which

Scenario Recommended Style Reason
Pure display, no children Inferred arrow Enforces explicitness; prevents accidental children
Layout wrappers (Card, Grid) FC<Props> Free children typing
Higher‑order components FC or custom generic Easier to compose
Design‑system libraries FC Newcomer readability
Strict null control FC Return type excludes undefined

4 Edge‑Case Gotchas

4.1 Hidden children

// Accepts children even if you didn't intend it
export const Toast: FC<ToastProps> = ({ message }) => <div>{message}</div>;
Enter fullscreen mode Exit fullscreen mode

4.2 memo() + FC

Older TS versions might lose generics:

export const Memoized = memo(GifList) as FC<Props>;
Enter fullscreen mode Exit fullscreen mode

4.3 forwardRef

Prefer explicit generics instead of FC:

export const Button = forwardRef<HTMLButtonElement, Props>(
  (props, ref) => <button ref={ref} {...props} />
);
Enter fullscreen mode Exit fullscreen mode

5 Migrating a Codebase

  1. Audit components — switch to arrow style if they never read children.
  2. ESLint — enable react/no-typos and related rules.
  3. Guidelines — document: “Atoms use arrows; slots use FC.”
  4. Prettier — keep consistent export style.

6 Cheat‑Sheet

Question Quick Answer
Does FC hurt runtime perf? No. Pure type import.
Is FC deprecated? No. Optional.
Default props with arrows? GifList.defaultProps = { gifs: [] }
Does FC type context? Only context?: any. Prefer hooks.

Final Thoughts

The choice signals intent more than anything:

  • Arrow inference → “Leaf node, no children.”
  • FC<Props> → “Drop stuff inside me.”

Use the one that documents intent best, lint ruthlessly, and iterate like the React‑TS scientist you are. 🧑‍🔬

✍️ Written by: Cristian Sifuentes – Full-stack dev crafting scalable apps with [NET - Azure], [Angular - React], Git, SQL & extensions. Clean code, dark themes, atomic commits

Happy coding — and may your prop types always align! 🚀

Top comments (0)