ElementType
컴포넌트의 유효한 indentifier여야 함
as라는 속성으로 받아온 엘리먼트 식별자를
Container로 만들어 줌
as는 타입이 ElementType
import { ElementType } from "react";
type ContainerProps = {
as: ElementType;
};
const Container = ({ as: Component }: ContainerProps) => {
return <Component />;
};
export default Container;
<Container as={Button}>Click Me</Container>
Children 받아오기
import { type ReactNode, type ElementType } from "react";
type ContainerProps = {
as: ElementType;
children: ReactNode;
};
const Container = ({ as: Component, children }: ContainerProps) => {
return <Component>{children}</Component>;
};
export default Container;
ComponentPropsWithoutRef 설정하기
동적으로 ElementType을 받아오므로,
해당 타입을 하드코딩 할 수 없다.
제네릭 타입을 활용
T는 구성요소 식별자.
그렇게 되면 T가 아무것이나 올 수 있으므로
extends로 ElementType을 사용하여
ElementType만 올 수 있게 제한해본다.
import {
type ReactNode,
type ElementType,
ComponentPropsWithoutRef,
} from "react";
type ContainerProps<T extends ElementType> = {
as: T;
children: ReactNode;
} & ComponentPropsWithoutRef<T>;
const Container = ({ as: Component, children }: ContainerProps) => {
return <Component>{children}</Component>;
};
export default Container;
그러면 아래와 같은 에러가 뜬다
구체적인 타입을 정의해야 하므로.
유효한 component identifier와 함께 사용되어야 하므로
하드코딩을 할 수는 없다.
함수의 유형을 받아들이는 제네릭 함수를 Container에 지정해본다.
ContainerProps는 제네릭 함수로 구체적으로 지정해야 하게 되었다. 그러므로 아래와 같이 지정해준다.
import {
type ReactNode,
type ElementType,
ComponentPropsWithoutRef,
} from "react";
type ContainerProps<T extends ElementType> = {
as?: T;
children: ReactNode;
} & ComponentPropsWithoutRef<T>;
const Container = <C extends ElementType>({
as,
children,
}: ContainerProps<C>) => {
const Component = as || "div";
return <Component>{children}</Component>;
};
export default Container;
ComponentPropsWithoutRef<T>속성 덕분에
...props도 사용할 수 있게 되었다.
모든 속성이 사용 가능하므로 onClick 속성도 사용 가능하다
<Container
as={Button}
onClick={() => {
console.log("clicked!");
}}
>
Click Me
</Container>
재활용 가능한 Card 컴포넌트
이런방식으로
Card 컴포넌트도 재활용할 수 있게 된다
actions라는 추가적 컴포넌트를 포함해서.
import { ReactNode } from 'react';
type CardProps = {
title: string;
children: ReactNode;
// "actions" is like an extra "slot" of this component
// It's the same type as the children prop, since we expect JSX code as a prop value
actions: ReactNode;
};
export function Card({ title, children, actions }: CardProps) {
return (
<section>
<h2>{title}</h2>
{children}
{actions}
</section>
);
}
// Example Usage:
export function Demo() {
return (
<Card
title="My Card"
actions={
<button onClick={() => console.log('Button clicked!')}>
Click Me!
</button>
}
>
<p>Some content</p>
</Card>
);
}
'공부기록 > Typescript' 카테고리의 다른 글
# 58 Form 래퍼 컴포넌트 타입지정 (0) | 2023.11.15 |
---|---|
#57 forwardRef의 타입지정 (0) | 2023.11.15 |
# 50 타입의 다양한 활용 유니언 타입, ComponentPropsWithoutRef, Button컴포넌트 (0) | 2023.11.15 |
useState / Formevent /setState / useRef 타입지정 (0) | 2023.11.15 |
props.children 타입 정의 방법 (0) | 2023.11.15 |