본문 바로가기
Development/TypeScript

ReactNode | ReactElement

by 개발자 데이빗 2021. 12. 20.

에러 로그

TS2322: Type 'false | Element' is not assignable to type 'ReactElement<any, string | JSXElementConstructor<any>>'.   Type 'boolean' is not assignable to type 'ReactElement<any, string | JSXElementConstructor<any>>'.

 

자바스크립트로 만들어진 프로젝트를 타입스크립트로 마이그레이션 하는 도중 위와 같은 에러를 만났다.

 

아래 예시 처럼 isSomthingTrue가 true인 경우에만 특정 엘리먼트를 반환하는 코드였는데

자바스크립트에서는 문제 없이 동작하였지만 타입 스크립트에서 ParentElement의 children props의 타입을 

ReactElement | ReactElement[] 로 지정하자 위와 같은 에러가 발생했다.

<View>
	{...}
    <ParentElement>
    	{isSomethingTrue && (
        	<Text>Something is true!!</Text>
        )}
    </ParentElement>
	{...}
</View>

 

해결 방식

위 코드 케이스의 경우 isSomethingTrue가 true인 경우 Text엘리먼트를 반환하지만 false인 경우에는 false를 그대로 반환하게 된다.

그러므로 boolean은 ReactElement의 타입에 맞지 않다는 에러를 발생시킨다.

적절한 타입을 찾던 중 ReactNode라는 타입을 발견하였다.

type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;

children props의 타입으로 ReactNode | ReactNode[]로 지정해준다면 에러가 났던 위의 코드를 사용할 수 있다.

그러나 ReactNode의 타입은 범위가 너무 넓어 엄격히 타입을 제한하고 싶다면 아래와 같이 빈 ReactFragment를 반환한다.

    <ParentElement>
    	{isSomethingTrue ? (
        	<Text>Something is true!!</Text>
        ) : (<></>)}
    </ParentElement>

 

그렇다면 ReactElement 와 ReactNode의 차이는 무엇일까?

React에서 작성되는 JSX는 바벨에 의해서 React.createElement(component, props, ...children) 함수로 트랜스파일된다.

이 React.createElement의 리턴타입이 ReactElement이다.

 

React의 type.d.ts 파일을 뒤적거리면 아래와 같은 React요소 관련된 타입들을 찾아볼 수 있는데

ReactNode는 ReactElement 기타 등등으로 볼 수 있겠다.

즉, ReactElement를 포함한 좀 더 유연한 넓은 범위의 타입이다.

function createElement<P extends {}>(
  type: FunctionComponent<P> | ComponentClass<P> | string,
  props?: Attributes & P | null,
  ...children: ReactNode[]): ReactElement<P>;

type ReactText = string | number;

interface ReactElement<P = any, T extends string | JSXElementConstructor<any> = string | JSXElementConstructor<any>> {
  type: T;
  props: P;
  key: Key | null;
}

type ReactChild = ReactElement | ReactText;

type ReactFragment = {} | ReactNodeArray;

type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;

 

댓글