Typescript(3) - Polymorphic Components
๐์์ํ๋ฉฐ
ํ๋ก๊ทธ๋จ ์ธ์ด์ ๋คํ์ฑ์ด๋, ํ๋ก๊ทธ๋จ ์ธ์ด์ ๊ฐ ์์๋ค์ด ๋ค์ํ ์๋ฃํ์ ์ํ๋ ๊ฒ์ด ํ๊ฐ๋๋ ์ฑ์ง์ ๊ฐ๋ฆฌํจ๋ค. (์ํค๋ฐฑ๊ณผ)
์ด์ฉ๋ค ๋ค์ด๊ฐ ์น์ฌ์ดํธ์์ Polymorphic Components ๊ด๋ จ๋ ๊ธ์ ๋ณด๊ฒ ๋์๋ค. Polymorphic(๋คํ์ฑ) ์ด๋ ๋จ์ด ์์ฒด๊ฐ ๋ฏ์ค์ด์, ์ด๊ฒ ๋ญ์ง? ํ๊ณ ์ฝ์ด๋ณด๋ ์์ค์, ๋ด๊ฐ ์์ ์ ๋ดค๋ ์ธ๊ฐ ์ ์๋์ด ์ฌ์ฉํ์๋ ๋ฐฉ์์ธ๊ฑธ ๊นจ๋ฌ์๋ค. ์ฌ์ง์ด ์ง๊ธ ๋ด๊ฐ ํ์๋ก ํ๋ ๋ด์ฉ์ด๋๊ฒ๋!
์ญ์ ์ฌ๋์ ๋ง๊ฐ์ ๋๋ฌผ(โฆ) ์ด๋ผ๊ณ ๊ทธ๋๋ ์~ ์ข์ ๋ฐฉ๋ฒ์ด๊ตฌ๋! ํ๊ณ ๋ ธ์ ์ ์ ๋ฆฌํด๋์๋๋ฐ ๊ทธ ์ดํ๋ก ์ฌ์ฉํ์ง ์์์ ๊น๋งฃ๊ฒ ์์ด๋ฒ๋ฆฌ๊ณ ๋ง์๋ค.. ๐
์ง๊ธ ์ ๋ฌด์ ์ ์ฉํ๊ธฐ๋ ์ข์ ๋ด์ฉ์ด๋ผ, ๋ด์ฉ์ ๊ผผ๊ผผํ ์ฝ์ด๋ณด์๋๋ฐ, ์ ์ฒด์ ์ธ ๋ด์ฉ ์์ฒด๋ ์ด๋ ต์ง ์์ง๋ง ์์ธ์ ๋ณต๋ณ์ Typescript๋ฅผ ํด์ํ๋ ๊ฒ์ด์๋ค.
๊ทธ๋์ ์ด๋ฒ ํฌ์คํ ๋ Typescript ์นดํ ๊ณ ๋ฆฌ์ ๋ฃ์ด๋์๋๋ฐ, ์ด๋ฒ ๊ธฐํ์ ์ ๋ค๋ฆญ ๊ฐ๋ ์ ๋ค์ ํ ๋ฒ ์ ๋ฆฌํด๋ณด๋ฉด์, Polymorphic Components๋ฅผ ๋ง๋ค์ด๋ณด์.
โ Polymorphic Components์ ํ์์ฑ
ํ์ฌ ๋ด๊ฐ ๋ด๋นํ๋ ์
๋ฌด ์ค์, url์ ๊ฐ์ง data๋ฅผ fetchํด์์, url์ธ ๊ฒฝ์ฐ <Link>
ํ๊ทธ๋ฅผ ๋ง๋ค๊ณ , ์๋ค๋ฉด <div>
ํ๊ทธ๋ฅผ ์ด์ฉํด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ์๋ค.
๋์ CSS๋ ๊ฐ์์ผ ํ๊ธฐ ๋๋ฌธ์ ์ค๋ก์ง HTML ํ๊ทธ๋ฅผ ์ํด์ ์๋์ ๊ฐ์ด ์ผํญ์ฐ์ฐ์๋ฅผ ์จ์ฃผ์ด์ผ ํ๋ค.
1
2
3
{
data.url ? <Link href={data.url}>{data}</Link> : <div>{data}</div>
}
ํด๋น ์์ ์์๋ ๊ฐ๋จํ๊ฒ ์ผ์ง๋ง ์ค์ ์ ๋ฌด์์๋ tailwind๋ฅผ ์ฌ์ฉํ๊ณ ์๊ธฐ ๋๋ฌธ์ ํด๋น ๊ฐ element๊ฐ ๊ต์ฅํ ๊ธธ์ด์ง๊ณ , ๋ CSS๋ฅผ ๋ฐ๊พธ๋ ค๋ฉด ๋ ํ๊ทธ๋ฅผ ๋ชจ๋ ๋ฐ๊ฟ์ฃผ์ด์ผ ํ๋ ๊ฒ์ด ์๋นํ ๊ท์ฐฎ์๋ค.๐ค
์ด๋ Polymorphic Components๊ฐ ๋ฑ์ฅํ๋ค. ์์์ ๋คํ์ฑ์ด ๋ฌด์์ธ์ง ์จ๋์๋๋ฐ, Polymorphic Components๋ ๊ฐ๋จํ ๋งํด props๋ก ํด๋น ํ๊ทธ๊ฐ ๋ฌด์์ธ์ง ์ง์ ํด์ฃผ๊ณ , ๋ด๊ฐ ์ง์ ํ HTML tag ์์ฑ์ ๋ด๋ ค์ ํ์์ ๋ฐ๋ผ Link๋ก๋, div๋ก๋ ์ธ ์ ์๋ ์ปดํฌ๋ํธ๋ฅผ ๋งํ๋ค.
์ด๊ฒ์ ์ด์ฉํ๋ฉด tailwind class๋ ํ ๋ฒ๋ง ์์ฑํ๊ณ , props ๋ด๋ ค์ฃผ๋ ๊ฒ์ ๋ฐ๊พธ์ด, ํ์์ ๋ฐ๋ผ <Link>
๋ก๋, <div>
๋ก๋ ๋ง๋ค ์ ์๊ฒ ๋๋ค.
โ Polymorphic Components ์ ์ฒด ์ฝ๋
์ด ์ฝ๋๋ Polymorphic Components๋ฅผ ๋ง๋๋ ์ฝ๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import React from "react"
type PolymorphicProps<C extends React.ElementType> = {
as?: C
children: React.ReactNode
} & React.ComponentPropsWithoutRef<C>
const Components = <C extends React.ElementType = "div">({
as,
children,
...props
}: PolymorphicProps<C>) => {
const Component = as || "div"
return <Component {...props}>{children}</Component>
}
์ค์ ์ฌ์ฉํ ๋๋ ๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉํ ์ ์๋ค.
1
2
3
4
//as๋ก a ํ๊ทธ๋ฅผ ๋ง๋ค์ด๋ณด์!
<Components as="a" href="http://test.com" />
//์ค์ ๋ ๋๋ง์ ์ด๋ ๊ฒ..
<a href="http://example.com"></a>
1
2
3
4
//as๋ก divํ๊ทธ๋ฅผ ๋ง๋ค์ด๋ณด์!
<Components as="div" />
//์ค์ ๋ ๋๋ง์ ์ด๋ ๊ฒ..
<div></div>
์ฆ ์์์ ๋ณด์๋ ์์๋ฅผ ์๋์ ๊ฐ์ด ์ ์ ์ ์๋ค.
1
2
3
4
5
6
<Components
as={data.url ? "a" : "div"}
{...(data.url ? { href: data.url } : {})}
>
{data.content}
</Components>
โ Polymorphic Components์ Typescript ํด์ํ๊ธฐ
Polymorphic Components๋ฅผ ๋ง๋ค ๋๋, typescript๋ฅผ ์ ๊ทน ํ์ฉํด ๋ณด๋ค ์์ ํ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค ์ ์๋ค.
๊ฐ๋ฐ์๊ฐ ์ค์๋ก div
๊ฐ ์๋ divv
๋ฅผ ๋ด๋ ค์ฃผ๊ฑฐ๋, button
ํ๊ทธ์ธ๋ฐ href
๋ฅผ ๋ด๋ ค์ฃผ๋ ค๊ณ ์๋ํ๋ ๊ฒ์ ๋ง์์ฃผ๊ธฐ ๋๋ฌธ์ด๋ค.
๊ทธ๋ผ ๋จผ์ ์์์ ๋ถํฐ ์ฐจ๋ก๋๋ก ํด์ํด๋ณด์.
1
2
3
4
type PolymorphicProps<C extends React.ElementType> = {
as?: C
children: React.ReactNode
} & React.ComponentPropsWithoutRef<C>
type PolymorphicProps
- PolymorphicProps๋ ์ด๋ฆ์ type์ ์ง์ ํด์ค๋ค๋ ๋ป์ด๋ค.
<C extends React.ElementType>
- ์ ๋ค๋ฆญ ํ์ C๊ฐ React.ElementType์ผ๋ก ์ ํ ๋๋ค๋ ์๋ฏธ๋ค.
- :star: ์ ๋ค๋ฆญ ํ์
์ โ์ฌ์ฉํ ๋ ๊ฒฐ์ โ ๋๋ค. ์ฆ,
React.ElementType
์ค ์ฌ์ฉ์๊ฐ ์ง์ ํ C ํ์ ์ ๋ฐ๋ผ PolymorphicProps์ ํ์ ์ด ๊ฒฐ์ ๋๋ค.- ์ด๋์ C๋ ๋ค์๊ณผ ๊ฐ์ด HTML ํ๊ทธ ์ด๋ฆ (โdivโ, โspanโ, โaโ ๋ฑ)์ด ๋๋ค. ์ฌ๊ธฐ์ ์ฃผ์ํ ์ ์ ์ด ์ฝ๋๊น์ง๋ C์ ๋ฒ์๋ฅผ ์ ์ํ ๊ฒ์ด๋ฉฐ,
PolymorphicProps<C>
๊ฐ ์ด๋ค ์์ฑ(href
,type
๋ฑ)์ ํ์ฉํ๋์ง๋ ์ ํ๋์ด ์์ง ์๋ค.
- ์ด๋์ C๋ ๋ค์๊ณผ ๊ฐ์ด HTML ํ๊ทธ ์ด๋ฆ (โdivโ, โspanโ, โaโ ๋ฑ)์ด ๋๋ค. ์ฌ๊ธฐ์ ์ฃผ์ํ ์ ์ ์ด ์ฝ๋๊น์ง๋ C์ ๋ฒ์๋ฅผ ์ ์ํ ๊ฒ์ด๋ฉฐ,
= { ... } & React.ComponentPropsWithoutRef<C>
- 2๋ฒ์ ํตํด C(tag)๋ฅผ ์ง์ ํ๋ค๋ฉด, ํด๋น tag์ ๋ฐ๋ผ ๋ด๋ ค์ค ์ ์๋ props๊ฐ ๋ฌ๋ผ์ง ๊ฒ์์ ์์ํ ์ ์๋ค. (a์ผ๋๋ง href๋ฅผ ๋ด๋ ค์ค๋ค ๋ฑ)
- ์ด ๋ถ๋ถ์ ํตํด ๊ตฌ์ฒด์ ์ผ๋ก ์ด๋ค props๋ฅผ ์ฌ์ฉํ ์ ์์์ง๋ฅผ ์ ์ํ๋ค.
{ ... }
์React.ComponentPropsWithoutRef<C>
๋ ๊ต์ฐจํ์ (A & B)๋ก์, A์ B์ ์์ฑ์ ๋ชจ๋ ๊ฐ์ง๋ ํ์ ์ด๋ค.
๊ทธ๋ค์์๋ ์ค์ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค ๋ ์ฌ์ฉ๋ ํ์ ์คํฌ๋ฆฝํธ๋ฅผ ํด์ํด๋ณด์.
1
2
3
4
5
6
7
8
const Components = <C extends React.ElementType = "div">({
as,
children,
...props
}: PolymorphicProps<C>) => {
const Component = as || "div"
return <Component {...props}>{children}</Component>
}
Components = <C extends React.ElementType = "div">
- ์ปดํฌ๋ํธ๋ฅผ ํธ์ถํ ๋ C์ ํ์ ์ ๊ฒฐ์ ํ๊ฒ ๋ค๋ ์๋ฏธ
:PolymorphicProps<C>
- ์์์ ์ ์ํ
PolymorphicProps
ํ์ ์ ํด๋น ์ปดํฌ๋ํธ์ props ํ์ ์ผ๋ก ์ง์ ํ๋ค. ์ฆ, C์ ๋ง๋ ์์ฑ๋ค์ ํฌํจํ๋ ํ์ ์ด ๋๋ค.
- ์์์ ์ ์ํ
์ด๋ฌํ ๊ณผ์ ์ ํตํด ์์ ํ Polymorphic ์ปดํฌ๋ํธ๊ฐ ๋ง๋ค์ด ์ง๋ค.