1. 클래스 컴포넌트 타입
interface Component<P = {}, S = {}, SS = any>
extends ComponentLifecycle<P, S, SS> {}
class Component<P, S> {
/* 생략 */
}
class PureComponent<P = {}, S = {}, SS = any> extends Component<P, S, SS> {}
- P, S는 props와 상태를 의미
- props와 state를 제네릭으로 받고 있다.
interface WorkerProps {
authrization: string;
}
class Worker extends React.Component<WorkerProps> {}
2. 함수 컴포넌트 타입
- 리액트 v18에서 React.VFC가 삭제되었다.
- React.FC에서 children이 사라졌다.
interface Workder {
authrization: string;
}
const Worker = ({ authrization }: Worker) => {};
3. Children props 타입 지정
type PropsWithChildren<P> = P & { children?: ReactNode | undefined };
- ReactNode는 ReactElement외에도 boolean, number 등 여러 타입을 포함하고 있는 타입이다.
- 더 구체적으로 타이핑 하는 용도로는 적합하지 않다.
- 특정 문자열만 허용하고 싶다면 구체적으로 타입을 지정하면 된다.
//example 1
type FrontendWorkerProps = {
children: "엄문주" | "성은지" | "고현수" | "박윤국";
};
//example 2
type FrontendWorkerProps = {
children: string;
};
//example 3
type FrontendWorkerProps = {
children: ReactElement;
};
4. render 메서드와 함수 컴포넌트의 반환 타입 - React.ReactElement vs JSX.Element vs React.ReactNode
ReactElement
- 함수 컴포넌트의 반환 타입이다.
interface ReactElement<P = any, T extends string | JSXElementConstructor<any> = string|JSXElementConstructor<any>{
type: T;
props: P;
key: Key | null;
}
- React.createElement를 호출하는 형태의 구문으로 변환하면 React.createElement의 반환 타입은 ReactElement이다.
- 가상 DOM의 엘리먼트는 ReactElement의 형태로 저장된다.
- ReactElement타입은 리액트 컴포넌트를 객체 형태로 저장하기 위한 포멧이다.
- JSX는 createElement 메서드를 호출하기 위한 문법이다. JSX는 리액트 엘리먼트를 생성하기 위한 문법이며 트랜스파일러는 JSX 문법을 createElement 메서드 호출문으로 변환하여 리액트 엘리먼트를 생성한다.
const element = React.createElement(
"h1",
{ className: "greeting" },
"Hello, world!"
);
- 리액트는 리액트 엘리먼트 객체를 읽어서 DOM을 구성한다.
- 리액트에는 여러 개의 createElement 오버라이딩 메서드가 존재하고, 이 매서드들이 반환하는 타입은 ReactElement 타입을 기반으로 한다.
- 정리 : ReactElement 타입은 JSX의 createElement 메서드 호출로 생성된 리액트 엘리먼트를 나타내는 타입이다.
사용 예시
- 추론 관점에서 더 유용하게 활용할 수 있는 방법은 JSX.Element 대신 ReactElement를 사용하는 것이다.
interface IconProps {
size: number;
}
interface Props {
// ReactElement의 props 타입으로 IconProps 타입 지정
icon: React.ReactElement<IconProps>;
}
const Item = ({ icon }: Props) => {
// icon prop으로 받은 컴포넌트의 props에 접근하면, props의 목록이 추론된다.
const iconSize = icon.props.size;
reutnr(<li>{icon}</li>);
};
JSX.Element
- JSX.Element 타입은 리액트의 ReactElement를 확장하고 있는 타입이다.
- 글로벌 네임스페이스에 정의되어 있어 외부 라이브러리에서 컴포넌트 타입을 재정의 할 수 있는 유연성을 제공한다.
[!NOTE] 글로벌 네임스페이스 식별자가 정의되는 전역적인 범위를 말한다. 어느곳에서든지 접근할 수 있다. 자바스크립트, 타입스크립트에서는 기본적으로 전역(글로벌) 스코프에서 선언된 변수나 함수 등은 글로벌 네임스페이스에 속한다.
declare global {
namespace JSX {
interface Element extends React.ReactElement<any, any> {}
}
}
- props와 타입 필드에 대해 any 타입을 가지도록 확장하고 있다.
사용예시
- props와 타입 필드가 any 타입인 리액트 엘리먼트를 나타낸다. 그래서 리액트 엘리먼트를 prop으로 전달받아 render props 패턴으로 컴포넌트를 구현할 때 유용하게 활용할 수 있다.
interface Props {
icon: JSX.Element;
}
const Item = ({ icon }: Props) => {
// prop으로 받은 컴포넌트의 props에 접근할 수 있다.
const iconSize = icon.props.size;
return <li>{icon}</li>;
};
// icon prop에는 JSX.Element 타입을 가진 요소만 할당할 수 있다.
const App = () => {
return <Item icon={<Icon size={14} />} />;
};
- JSX 문법만 삽입할 수 있게 된다.
- icon.props에 접근하여 prop으로 넘겨받은 컴포넌트의 상세한 데이터를 가져올 수 있다.
ReactNode
type ReactText = string | number;
type ReactChild = ReactElement | ReactText;
type ReactFragment = {} | Iterable<ReactNode>; // ReactNode의 배열 형태
type ReactNode =
| ReactChild
| ReactFragment
| ReactPortal
| boolean
| null
| undefined;
- ReactElement 외에도 boolean, string, number 등의 여러 타입을 포함하고 있다.
- ReactChild 타입은 ReactElement | string | number로 정의되어 ReactElement보다는 좀 더 넓은 범위를 갖고 있다.
- ReactNode는 리액트의 render 함수가 반환할 수 있는 모든 형태를 담고 있다.