TypeScript
emotion-variants는 스타일 정의에서 variant 타입을 알아서 추론해요. 이 페이지에서는 ev() 결과에서 React 컴포넌트 props를 끌어내, 컴포넌트의 props 타입과 스타일이 항상 같이 움직이도록 만드는 방법을 다뤄요.
VariantProps 타입
emotion-variants는 VariantProps를 export해요. ev() 결과의 타입을 넘기면 variant 타입을 끌어낼 수 있어요.
import { ev, type VariantProps } from 'emotion-variants';
const button = ev({
variants: {
size: {
small: {},
medium: {},
large: {},
},
color: {
primary: {},
danger: {},
},
},
});
type ButtonVariants = VariantProps<typeof button>;
// { size?: 'small' | 'medium' | 'large'; color?: 'primary' | 'danger' }variants.size에 새 값을 추가하면 ButtonVariants['size']도 자동으로 따라와요.
HTML 요소 props와 결합
button처럼 HTML 요소를 감싸는 컴포넌트라면 ComponentPropsWithoutRef와 교집합 타입으로 묶어 줘요.
import type { ComponentPropsWithoutRef } from 'react';
export type ButtonProps = ComponentPropsWithoutRef<'button'> & ButtonVariants;
export function Button({ size, color, ...rest }: ButtonProps) {
return <button css={button({ size, color })} {...rest} />;
}기본값과 함께 쓰기
기본값은 defaultVariants 한 곳에만 선언하고, props는 그대로 넘기세요. 생략된 prop은 undefined로 도착해도 기본값으로 해석되기 때문에, prop 경계에 기본값을 한 번 더 두면 두 값이 어긋날 자리만 생겨요.
const button = ev({
variants: {
/* ... */
},
defaultVariants: {
size: 'medium',
color: 'primary',
},
});
export function Button({ size, color, ...rest }: ButtonProps) {
return <button css={button({ size, color })} {...rest} />;
}해석 규칙은 Default Variants에서 확인하세요.
ref 전달
import { forwardRef, type ComponentPropsWithoutRef } from 'react';
export type ButtonProps = ComponentPropsWithoutRef<'button'> & ButtonVariants;
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
({ size, color, ...rest }, ref) => (
<button ref={ref} css={button({ size, color })} {...rest} />
),
);일부 축만 노출하기
특정 축(예: density)을 공개 API에서 숨기고 싶다면 Pick을 써 주세요.
type PublicButtonProps =
ComponentPropsWithoutRef<'button'> &
Pick<ButtonVariants, 'size' | 'color'>;디자인 시스템에서 re-export
emotion-variants를 내부에서 쓰는 디자인 시스템 패키지를 만든다면, props 타입을 함께 export해서 사용자가 내부 스타일 파일을 직접 import하지 않아도 되게 해 주세요.
// design-system/src/button/index.ts
export { Button } from './button';
export type { ButtonProps } from './button';사용자는 패키지에서 ButtonProps만 import하면 되고, 내부 ev() 스타일 정의는 만질 일이 없어요.
함께 보기
GitHub에서 이 페이지 편집
마지막 업데이트