AsChild 패턴 (Radix UI)
컴포넌트 기능은 유지하면서 렌더링 요소를 변경:
<Button asChild>
<a href="/home">Link Button</a>
</Button>
핵심 구현 - Slot 컴포넌트:
const Slot = forwardRef(({ children, ...props }, ref) => {
if (!isValidElement(children)) return null
return cloneElement(children, {
...props,
...children.props,
ref: ref || children.ref,
})
})
자식 요소 타입에 따른 조건부 Props:
type ConditionalProps<T> = T extends ReactElement<any, 'a'>
? { href?: string; external?: boolean }
: T extends ReactElement<any, 'button'>
? { type?: 'button' | 'submit' }
: {}
// 사용
;<Anchor href="/home" external>
{' '}
{/* a 태그일 때만 href 허용 */}
<a>Link</a>
</Anchor>
활용: 디자인 시스템, 라우터 통합 (<Button asChild><NextLink /></Button>)