diff --git a/README.md b/README.md index 2b2d545..e1fa9d9 100644 --- a/README.md +++ b/README.md @@ -524,7 +524,8 @@ export default function Home() { import { compileMDX } from 'next-mdx-remote/rsc' export default async function Home() { - const { content, frontmatter } = await compileMDX({ + // Optionally provide a type for your frontmatter object + const { content, frontmatter } = await compileMDX<{ title: string }>({ source: `--- title: RSC Frontmatter Example --- diff --git a/__tests__/rsc.test.tsx b/__tests__/rsc.test.tsx new file mode 100644 index 0000000..d0d885b --- /dev/null +++ b/__tests__/rsc.test.tsx @@ -0,0 +1,21 @@ +import { compileMDX } from '../rsc' + +describe('compileMDX', () => { + test('frontmatter types', async () => { + const { frontmatter } = await compileMDX<{ title: string }>({ + source: `--- +title: 'Hello World' +--- + +# Hi`, + options: { + parseFrontmatter: true, + }, + }) + + expect(frontmatter.title).toEqual('Hello World') + + // @ts-expect-error -- blah does not exist on the frontmatter type + expect(frontmatter.blah).toBeUndefined() + }) +}) diff --git a/src/rsc.tsx b/src/rsc.tsx index 650ae14..c14c4cf 100644 --- a/src/rsc.tsx +++ b/src/rsc.tsx @@ -10,10 +10,7 @@ import { VFileCompatible } from 'vfile' import { MDXProvider } from '@mdx-js/react' import { serialize } from './serialize' -export type MDXRemoteProps = Omit< - MDXRemoteSerializeResult, - 'compiledSource' -> & { +export type MDXRemoteProps = { source: VFileCompatible options?: SerializeOptions /** @@ -27,12 +24,20 @@ export type MDXRemoteProps = Omit< export { MDXRemoteSerializeResult } -export async function compileMDX({ +export type CompileMDXResult> = { + content: React.ReactElement + frontmatter: TFrontmatter +} + +export async function compileMDX>({ source, options, components = {}, -}: MDXRemoteProps) { - const { compiledSource, frontmatter, scope } = await serialize( +}: MDXRemoteProps): Promise> { + const { compiledSource, frontmatter, scope } = await serialize< + Record, + TFrontmatter + >( source, options, // Enable RSC importSource diff --git a/src/serialize.ts b/src/serialize.ts index 882d634..43c7e86 100644 --- a/src/serialize.ts +++ b/src/serialize.ts @@ -38,7 +38,10 @@ function getCompileOptions( /** * Parses and compiles the provided MDX string. Returns a result which can be passed into to be rendered. */ -export async function serialize( +export async function serialize< + TScope = Record, + TFrontmatter = Record +>( source: VFileCompatible, { scope = {}, @@ -46,7 +49,7 @@ export async function serialize( parseFrontmatter = false, }: SerializeOptions = {}, rsc: boolean = false -): Promise { +): Promise> { const vfile = new VFile(source) // makes frontmatter available via vfile.data.matter @@ -66,8 +69,7 @@ export async function serialize( return { compiledSource, - frontmatter: - (vfile.data.matter as Record | undefined) ?? {}, - scope, + frontmatter: (vfile.data.matter ?? {}) as TFrontmatter, + scope: scope as TScope, } } diff --git a/src/types.ts b/src/types.ts index f36c02e..6303a9f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -39,9 +39,9 @@ export type MDXRemoteSerializeResult< * For example, in cases where you want to provide template variables to the MDX, like `my name is {name}`, * you could provide scope as `{ name: "Some name" }`. */ - scope?: TScope + scope: TScope /** * If parseFrontmatter was set to true, contains any parsed frontmatter found in the MDX source. */ - frontmatter?: TFrontmatter + frontmatter: TFrontmatter }