템플릿 리터럴 타입으로 prop 이름을 만든다 — 매핑 타입이 union 멤버를 하나씩 K 로 돌고, as 가 `render${K}` 로 이름을 바꾼다.1
import * as React from 'react'
type RenderPropNames = 'Title' | 'Content' | 'Actions'
type RenderProps = {
[K in RenderPropNames as `render${K}`]: () => React.ReactNode
}
type Props = RenderProps
/**
* @example
*
* ```tsx
* <DialogComponent
* renderTitle={() => <h2>Title</h2>}
* renderContent={() => <p>Content</p>}
* renderActions={() => (
* <div>
* <button onClick={handleClose}>Close</button>
* <button onClick={handleSubmit}>Submit</button>
* </div>
* )}
* />
* ```
*/
function Dialog({
renderTitle,
renderContent,
renderActions,
}: Props) {
return (
<div data-scope="root">
<div data-part="content">
{renderTitle()}
{renderContent()}
</div>
<div data-part="actions">{renderActions()}</div>
</div>
)
}
Footnotes
-
TypeScript Handbook — Mapped Types, Key Remapping via
as(TS 4.1+): “You can leverage features like template literal types to create new property names from prior ones”.K가 멤버 하나일 때 템플릿 리터럴은 “produces a new string literal type by concatenating the contents”. ↩