tsx
Dynamically render blocks in PayloadCMS
The satisfies keyword is perfect here because it validates the object shape against Record<BlockSlug, ComponentType<any>> without widening the type. This means TypeScript will error at compile time if you add a new block type in Payload but forget to add the corresponding component. Unlike a type annotation (: Record<...>), satisfies preserves the narrow literal types of the keys, giving you autocomplete and strict key checking while still enforcing the constraint.
import type { Page } from "@/payload-types"
import type { BlockSlug } from "payload"
import type { ComponentType } from "react"
export function RenderBlocks({ blocks }: { blocks: Page["content"][0][] }) {
return blocks.map((block, index) => {
if (!(block.blockType in blockComponents)) {
return null
}
const Block = blockComponents[block.blockType]
return (
<div key={index}>
{/* @ts-expect-error block props should be correct at this point */}
<Block {...block} />
</div>
)
})
}
const blockComponents = {
pageTitle: PageTitleBlock,
sectionHeader: SectionHeaderBlock,
anchorNavigation: AnchorNavigationBlock,
textImage: TextImageBlock,
productCardGrid: ProductCardGridBlock,
topicTeaser: TopicTeaserBlock,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} satisfies Record<BlockSlug, ComponentType<any>>typescriptreactpayloadcms
lubosmato