Typescript를 사용하면서 가장 어렵다고 생각하는 부분이 컴포넌트나 기타 라이브러리의 타입을 어떻게 지정하는가에 대한 부분이라고 생각한다.
오늘도 React.Element를 찾다가 StackOverFlow에 좋은 답변이 있어서 정리해보려고 한다.
React.element는 type과 props를 가진 객체이다.
type Key = string | number
interface ReactElement<P = any, T extends string | JSXElementConstructor<any> = string | JSXElementConstructor<any>> {
type : T;
props : P;
key: Key | null;
}
ReactNode는 ReactElement, ReactFragment, string, number, ReactNode의 Array, null, undefined, boolean이다.
type ReactText = string | number;
type ReactChild = ReactElement | ReactText;
interface ReactNodeArray extends Array<ReactNod> {}
type ReactFragment = {} | ReactNodeArray;
type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;
JSX.Element는 props와 type이 any인 제네릭 타입을 가진 ReactElement이다. JSX는 글로벌 네임 스페이스에 있기 때문에 다양한 라이브러리에서 자체 라이브러리의 방법대로 실행 될 수 있다.
리액트의 경우 다음과 같이 실행된다.
declare global {
namespace JSX {
interface Element extends React.ReactElement<any, any> {}
}
}
예시
<p> // ReactElement = JSX.Element
<Custom> // ReactElement = JSX.Element
{true && 'test'} // ReactNode
</Custom>
</p>
render(): ReactNode;
interface StatelessComponent<P = {}> {
(props: P & { children? : ReactNode }, context?: any): ReactElement | null;
}
✏️ Class Component는 ReactNode를 타입으로 지정한다. ReactNode는 그 자체로 다양한 타입을 지니기 때문에 충분!
✏️ Functional Component는 ReactElement는 object 형태로 null 값을 가지고 있지 않기 때문에 union을 사용해서 null 값을 줘야한다. 💯 ReactElement | null
const Example = () : ReactElement | null => {
if(condition) {
return null;
};
return <h1>Hello World</h1>
};