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>;
뭔가 불편할 것 같지만 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
로 복구하는 방법이 있지만 특별한 경우가 아니라면 모르셔도 될 것 같습니다.