초보 개발자의 성장 일기

[TypeScript] 래퍼 컴포넌트를 작성할 때 타입 오류 본문

Development/TypeScript

[TypeScript] 래퍼 컴포넌트를 작성할 때 타입 오류

YUNA 2024. 3. 15. 21:49

사이즈 별로 div 컴포넌트를 만들었고, "medium"을 props로 넣어주면 설정해준 width, height가 나오는데 props를 지정하면 컴포넌트에 에러가 났다.

 

'{ children: Element; size: string; }' 형식은 'IntrinsicAttributes & Size' 형식에 할당할 수 없습니다.

'IntrinsicAttributes & { size: Size; }' 형식에 'children' 속성이 없습니다.

 

return (
    <>
      <Container size="medium"> // 에러
        <S.User>
          <div>
            <img src={image} />
          </div>
        </S.User>
      </Container>
    </>
  );
}

 

 

Container에는 아래와 같이 컴포넌트를 만들었다.

import { StyledContainer } from '@/src/components/Home/Container/Container.styles';

type Size = 'small' | 'medium' | 'large';

function Container(size: Size) {
  return <StyledContainer size={size}></StyledContainer>;
}

export default Container;

 

 

 

IntrinsicAttributes의 뜻을 검색해보니 '본질적인 속성'이었다.

props로 넘겨준 size를 컴포넌트 파일에서 받지 못하는건가 싶어서 찾아보다가,

ReactNode를 작성하면 에러가 사라진다는 글을 보고 children에 React.ReactNode를 작성해주었더니 에러가 사라졌다.

 

import { StyledContainer } from '@/src/components/Home/Container/Container.styles';

type Size = 'small' | 'medium' | 'large';

type ContainerProps = {
  size: Size;
  children: React.ReactNode;
};

function Container({ size }: ContainerProps): JSX.Element {
  return <StyledContainer size={size}></StyledContainer>;
}

export default Container;

 

자식 요소를 감싸는 래퍼 컴포넌트를 작성할 때 자식 요소인 children 속성의 타입을 명시해야 한다고 한다.

 

ReactNode외에도 ReactChildReactElement가 있었다.

이 세가지 차이에 대해 궁금해져서 더 자세히 공부했다.

 

 

◾️ React.ReactNode

ReactNode 타입은 jsx 내에서 사용할 수 있는 모든 요소의 타입이며 stringnullundefined 등을 포함하는 가장 넓은 범위를 갖는 타입이다.

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

 

 

◾️ React.ReactChild

type ReactChild = ReactElement | ReactText;

ReactElement타입과ReactText (string, number) 포함한다.

 

 

◾️ React.ReactElement

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

ReactElement  createElement 함수를 통해 생성된 객체의 타입이다.

ReactNode 와는 달리 원시 타입을 허용하지 않고 완성된 객체(컴포넌트) 요소만을 허용한다.

자식 요소로 하나의 "컴포넌트" 를 받는 것을 강제해야 하는 상황에 사용한다.

 

 

ReactNode  ReactElement 의 큰 차이점 javascript 의 원시타입의 허용 유무의 차이이다.

컴포넌트를 자식으로 받아서 사용하려고 하는 경우에는 ReactElement를 사용하는 것이 좋다.

타입별 허용 범위 : ReactNode > ReactChild > ReactElement

 

import { StyledContainer } from '@/src/components/Home/Container/Container.styles';

type Size = 'small' | 'medium' | 'large' | 'long';

type ContainerProps = {
  size: Size;
  children: React.ReactElement;
};

function Container({ size, children }: ContainerProps) {
  return <StyledContainer size={size}>{children}</StyledContainer>;
}

export default Container;

자식 컴포넌트들도 타입을 지정해줬고, props로 자식 컴포넌트를 넘겨서 지정해주었더니 정상적으로 잘 작동한다.