리액트 18의 타입스크립트 타입 변경점

Posted on 2022-04-28

React(리액트) 18이 얼마 전에 출시했습니다. 개발하시는 프로젝트에 이미 업데이트 했거나 조만간 업데이트 하실 계획일텐데요.

리액트와 Typescript(타입스크립트)를 같이 사용했던 프로젝트라면 반드시 수정해야 할 타입 정의의 브레이킹 체인지 몇가지 공유드립니다.

  • React.FC 타입에서 암묵적인 children 선언 제거
  • ReactFragment 타입에서 {} 제거
  • this.context는 이제 unknown 타입

어차피 검색하게 되실 겁니다. 미리 파악해두시면 좋을 것 같아요 :)

React.FC 타입에 암묵적인 children 선언 제거

약간 놀라실 분도 계실 텐데요. 자바스크립트와 리액트를 사용하시다가 타입스크립트를 나중에 적용하셨다면 대부분 검색하셨던 것 중 하나가 아마 프롭으로 children을 어떻게 선언해야 하나였을 겁니다. 검색하신 후 React.FC를 사용하는 것으로 해결하셨을 텐데요. React.FC에서 children 관련 선언이 모두 제거됩니다.

그래서 리액트를 업데이트하자마자 children을 사용했던 기존 코드는 죄다 에러와 함께 빨간불이 뜰 겁니다.

const Example: React.FC = ({ children }) => <div>{children}</div>;
// "TS2339: Property 'children' does not exist on type '{}'."

뭔가 불편할 것 같지만 children이라는 암묵적이었던 일종의 키워드는 자식 노드가 필요한지 아닌지의 의도를 명확하게 드러낼 수 없다는, 타입의 관점에서는 꽤 크리티컬한 문제를 갖고 있었습니다. 타입에 자식 노드가 꼭 필요한 컴포넌트에 자식 노드를 넣지 않았을 경우 혹은 그 반대의 경우를 타입으로 잡아내지 못한다는 단점이 있었죠.

그래서 암묵적으로 선언됐던 children을 명시적으로 컴포넌트에 맞게 선언을 하자는 취지입니다. 저는 매우 동의합니다.

이렇게 말이죠.

type Props = {
  children: React.ReactNode;
};

const Example: React.FC<Props> = ({ children }) => <div>{children}</div>;

이 컴포넌트는 자식 컴포넌트가 꼭 필요하다는 의도를 타입으로 정의했습니다.

자식 노드가 옵셔널 한 경우는 옵셔널로 선언하면 되겠죠?

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

아마 기존의 React.FC안에서도 옵셔널 이었을겁니다.

매번 저렇게 선언하기 싫지만 그래도 뭔가 표준적인 방법을 원하시는 분은 PropsWithChildren를 사용할 수도 있습니다.

type Props = {
  title?: string;
};

const Example: React.FC<React.PropsWithChildren<Props>> = ({ children }) => <div>{children}</div>;

근데 왠지 코드가 더 복잡해진 느낌입니다. 제너릭이 겹칠수록 코드는 복잡해집니다. 저는 이번 변경의 의도대로 children을 그때그때 선언하는 방법이 더 좋아 보입니다.

ReactFragment 타입에서 {} 제거

children의 변경으로 생긴 추가 변경점이지만 굳이 모르셔도 되는 내용입니다. ReactFragment 타입에서 {} 즉 객체가 제거됐습니다. 일반 객체로 자식 노드를 만드는 건 이미 14버전부터 지원하지 않았지만 그동안 타입에서는 암묵적인 children 때문에 유지해왔습니다. 이번 변경으로 같이 제거됐습니다.

this.context 는 이제 unknown 타입

그동안은 any타입이었습니다. 모호하고 타입 친화적이지 않았었죠. 이제는 unknown 타입입니다. 반드시 명확한 타입으로 캐스팅해서 써야 합니다. 기존의 any로 복구하는 방법이 있지만 특별한 경우가 아니라면 모르셔도 될 것 같습니다.

♥ Support writer ♥
with kakaopay

크리에이티브 커먼즈 라이선스이 저작물은 크리에이티브 커먼즈 저작자표시-비영리-변경금지 4.0 국제 라이선스에 따라 이용할 수 있습니다.

© Sungho Kim2022