유니언 타입
1. 프로퍼티를 union타입으로 구성
mode 속성을
해당 타입으로만 지정할 수 있게 만듦
2. 옵셔널 프로퍼티
props로 severity를 넣을 수도 있고
안넣을 수도 있게 구성
import { type ReactNode } from "react";
type InfoBoxProps = {
mode: "hint" | "warning";
severity?: "low" | "medium" | "high";
children: ReactNode;
};
const InfoBox = ({ children, mode, severity }: InfoBoxProps) => {
if (mode === "hint") {
return (
<aside className="infobox infobox-hint">
<p>{children}</p>
</aside>
);
}
return (
<aside className={`infobox infobox-warning warning--${severity}`}>
<h2>Warning</h2>
<p>{children}</p>
</aside>
);
};
export default InfoBox;
3. 타입을 유니언으로 설정
둘중 하나만 선택이 되며,
props로 severity를 넣을 수도 있고
안넣을 수도 있게 구성
그렇게하면 객체 구조분해할당은 안되고,
아래와 같이 상황에 맞춰 props를 구조분해할당을 사용해야 함
import { type ReactNode } from "react";
type HintBoxProps = {
mode: "hint";
children: ReactNode;
};
type WarningBoxProps = {
mode: "warning";
severity: "low" | "medium" | "high";
children: ReactNode;
};
type InfoBoxProps = HintBoxProps | WarningBoxProps;
const InfoBox = (props: InfoBoxProps) => {
const { mode, children } = props;
if (mode === "hint") {
return (
<aside className="infobox infobox-hint">
<p>{children}</p>
</aside>
);
}
const { severity } = props;
return (
<aside className={`infobox infobox-warning warning--${severity}`}>
<h2>Warning</h2>
<p>{children}</p>
</aside>
);
};
export default InfoBox;
그렇게 되면 mode props로 warning을 주었을 때는
severity를 하게하고
mode가 hint일 때는 severity를 주지 않도록
만들 수 있게 됨
ComponentPropsWithoutRef
아토믹한 Input 컴포넌트를 재활용 하기 위해
지정한 props이외에도 많은 내장 속성을 활용해 보려고 함
type InputProps = {
label: string;
id: string;
};
const Input = ({ label, id, ...props }: InputProps) => {
return (
<p>
<label htmlFor={id}>{label}</label>
<input id={id} type="text" {...props} />
</p>
);
};
export default Input;
그러려면 많은 프롭스들을 받아들여 줘야 하는데, 일일히 다 쓸순 없고
아래와 같이 하면 된다
import { ComponentPropsWithoutRef } from "react";
type InputProps = {
label: string;
id: string;
} & ComponentPropsWithoutRef<"input">;
const Input = ({ label, id, ...props }: InputProps) => {
return (
<p>
<label htmlFor={id}>{label}</label>
<input id={id} type="text" {...props} />
</p>
);
};
export default Input;
props가 anchorProps인지 buttonProps인지에 따라 다른 엘리먼트를 반환 해주기
(type predicate)
방법 1.
import { type ComponentPropsWithoutRef } from "react";
type ButtonProps = {
el: "button";
} & ComponentPropsWithoutRef<"button">;
type AnchorProps = {
el: "anchor";
} & ComponentPropsWithoutRef<"a">;
const Button = (props: ButtonProps | AnchorProps) => {
if (props.el === "anchor") {
return <a className="button" {...props}></a>;
}
return <button className="button" {...props}></button>;
};
export default Button;
방법2. 반환타입 props is AnchorProps 타입을 이용
import { type ComponentPropsWithoutRef } from "react";
type ButtonProps = ComponentPropsWithoutRef<"button">;
type AnchorProps = ComponentPropsWithoutRef<"a">;
const isAnchorProps = (
props: ButtonProps | AnchorProps
): props is AnchorProps => {
return "href" in props;
};
const Button = (props: ButtonProps | AnchorProps) => {
if (isAnchorProps(props)) {
return <a className="button" {...props}></a>;
}
return <button className="button" {...props}></button>;
};
export default Button;
그러나 이렇게 되면 타입스크립트의 타입제한을 받지 못하기 때문에
안정적이지 않은 이슈가 있을 수 있다
방법3. never를 이용하는 방법
button에서 절대 사용해서는 안되는 속성에 제한을 걸어두는 방법
import { type ComponentPropsWithoutRef } from "react";
type ButtonProps = ComponentPropsWithoutRef<"button"> & {
href?: never;
};
type AnchorProps = ComponentPropsWithoutRef<"a"> & {
href?: string;
};
이렇게 된다면 같이 넣을 수 없는 속성을
타입스크립트에게 알려주게 된다.
'공부기록 > Typescript' 카테고리의 다른 글
#57 forwardRef의 타입지정 (0) | 2023.11.15 |
---|---|
# 54 polymorphic component 만들기 : Container (0) | 2023.11.15 |
useState / Formevent /setState / useRef 타입지정 (0) | 2023.11.15 |
props.children 타입 정의 방법 (0) | 2023.11.15 |
화살표 함수에 제네릭 사용하기 (0) | 2023.11.14 |