TypeScript에서 Function Components와 React.FC: 균형 잡힌 토론

React 컴포넌트에서 TypeScript 타이핑의 진화를 이해하기

TypeScript에서 Function Components와 React.FC: 균형 잡힌 토론

React와 TypeScript가 함께 프로젝트에 참여했습니다. TypeScript가 말하길, "내가 타입 관리를 할게." React는, "내가 렌더링을 담당할게." 그 사이 누군가가 질문합니다:

React.FC를 써야 할까요, 아니면 함수에 바로 타입을 지정하는 게 나을까요?

합리적인 질문입니다. 언뜻 보면 React.FC는 다듬어지고 공식적이며, 세련되어 보이죠. 마치 코드에 와인 한 잔을 따라주며 "컴포넌트를 우아하게 만들어 보자"고 말하는 듯합니다. 하지만 속을 들여다보면, 현대 TypeScript가 거의 벗어나 온 짐짝 같은 면도 함께 가지고 있습니다.

좀 더 자세히 살펴봅시다.


두 가지 스타일

기본 함수 컴포넌트

type Props = { title: string };

function MyComponent({ title }: Props) {
  return <h1>{title}</h1>;
}

깔끔하고 명확하며 이해하기 쉽습니다. 블랙 커피처럼, 군더더기 없이 일을 해냅니다.

또는 화살표 함수 방식이 더 마음에 든다면:

const MyComponent = ({ title }: Props) => {
  return <h1>{title}</h1>;
};

둘 다 유효하고 가독성이 좋으며 현재 베스트 프랙티스와 잘 부합합니다.


React.FC 변형

import { FC } from 'react';

type Props = { title: string };

const MyComponent: FC<Props> = ({ title }) => {
  return <h1>{title}</h1>;
};

이 버전은 컴포넌트를 제네릭 타입으로 감쌉니다. 더 "공식적"으로 보이고, 최근 TypeScript 유틸리티 타입을 접했다면 자연스러운 느낌—비밀 클럽에 들어온 것 같은 느낌이 들 수도 있죠. 하지만 가끔은 비밀 클럽에도 주의 사항이 있습니다.


React.FC가 실제로 하는 일

React.FC(React.FunctionComponent의 줄임말)는 함수 컴포넌트를 설명하는 헬퍼 타입입니다. 몇 가지 기본 동작을 제공합니다:

  • 기본적으로 children prop을 포함합니다(필요 여부와 상관없이).
  • 특정 에디터에서 자동 완성 기능을 약간 향상시킬 수 있습니다.
  • 반환 타입을 좀 더 명시적으로 만들어 줄 수 있지만, 실제로는 거의 중요하지 않습니다.

이들은 작은 편의 기능이며, React + TypeScript 초창기에는 더 유용했습니다. 하지만 시간이 흐르면서 이런 "기능"들은 오히려 방해가 되는 경우가 많아졌습니다.


왜 인기가 시들해지고 있을까?

React.FC는 TypeScript에서 주머니가 많지만 대부분 사용하지 않는 카고 팬츠 같다고 할 수 있습니다.

  1. 암묵적 children 포함

모든 컴포넌트가 children prop을 받는데, 그 컴포넌트가 원하지 않아도 포함됩니다. 타입에 children이 있다고 가정해 버리면 개발자가 혼란스러운 버그를 만날 수 있습니다. (경고: 실제로 children이 없을 수도 있습니다.)

  1. 제네릭과 어울리지 않음

컴포넌트가 제네릭을 필요로 할 때, React.FC는 오히려 문법을 복잡하게 만들며, TypeScript가 덜 도움이 되게 만듭니다.

  1. 장황하지만 명확하지 않음

const MyComponent: FC<Props>라고 쓰는 것은 props를 직접 타입 지정하는 것보다 길고, 경우에 따라 이해하기 더 어렵습니다.

  1. 더 이상 필요하지 않음

React.FC를 쓰던 초기 이유들—에디터 지원, JSX 타입 추론 등—은 대부분 TypeScript의 발전으로 해결되었습니다. 그때는 현실적인 해결책이었지만, 지금은 구식 스타일일 뿐입니다.


비교 대조

특징 function Component() const Component: FC
children 포함? 선언한 경우에만 포함 항상 포함
제네릭 지원? 자연스럽게 지원 추가 노력이 필요
장황한가? 최소한 확연히 더 장황함
에디터 지원? 충분함 특정 경우에 약간 더 좋음
권장되는가? 더 이상 아님

권장되는 접근법

커뮤니티의 합의는 간단합니다: props를 직접 타입 지정하세요. 컴포넌트가 children을 받길 원하면 명시하세요. 그렇지 않으면 받지 않습니다. 이런 정직함이 미래의 당신에게 고마움으로 돌아옵니다.

type Props = {
  title: string;
  children?: React.ReactNode;
};

const MyComponent = ({ title, children }: Props) => (
  <div>
    <h1>{title}</h1>
    {children}
  </div>
);

명시적이고 유지보수에 용이하며, 컴포넌트가 children을 처리하지 않을 때까지 처리하는 척 하지 않습니다.


React.FC가 여전히 유용한 상황이 있을까?

가끔은 있습니다. 레거시 코드베이스에서 React.FC에 많이 의존하는 경우, 일관성을 유지하는 게 코드를 모두 다시 작성하는 것보다 더 중요할 수 있습니다. 빠르게 컴포넌트를 만들어야 하고 children 타입에 신경 쓰기 싫을 때, FC는 시간을 절약할 수도 있습니다.

하지만 일반적으로 그것들은 규칙을 증명해 주는 예외일 뿐입니다.


마무리하며

React.FC가 틀린 것은 아닙니다. 단지 더 이상 필수적이지 않을 뿐입니다. 현대 TypeScript는 React 컴포넌트 타입 지정을 더 간단하고 예측 가능하게 만들어주었습니다.

다음에 FC를 쓸 때는 잠시 멈춰서 그것이 진짜로 가치를 더하는지, 아니면 단지 불필요한 층만 늘리는지 생각해보세요. 대부분의 경우, 단순한 타입 지정 함수가 더 나은 선택일 것입니다.

소프트웨어도, 인생도 명확함이 영리함을 이깁니다. 그리고 놀라움이 적다는 것은 후회도 적다는 뜻이니까요.

Categories