React中MDX的实际类型是什么?如何精准指定参数类型?
如何在React项目中为MDX指定精准类型?
我在React项目中使用MDX,想明确MDX的实际类型,目前找不到对应的类型定义。我写了一个Main组件,其中自定义的MainProps类里的contentStack字段现在用的是React.JSX.Element[]类型,虽然MDX能适配这个类型,但我希望更精准地限定这个数组只能接受MDX相关的内容。
Main组件代码
'use client' import styles from "./main.module.css"; import React from "react"; import "./main" export class MainProps { constructor( public title: string, public contentStack: React.JSX.Element[] = [], public sectionOrArticle: "section" | "article" = "section", ) { } } export default function Main(props: { prop: MainProps }): React.JSX.Element { if (!props.prop.contentStack) { return ( <main className={styles.main}> <h2>{props.prop.title}</h2> </main> ) } return ( <main className={styles.main}> <h2>{props.prop.title}</h2> { props.prop.sectionOrArticle !== "article" ? props.prop.contentStack.map((item) => ( <section key={props.prop.contentStack!.indexOf(item)}> {item} </section> )) : props.prop.contentStack.map((item) => ( <article key={props.prop.contentStack!.indexOf(item)}> {item} </article> )) } </main> ) }
当前使用示例
'use client' import TaskContent from "./task.mdx" import React from "react"; import Header from "@/app/components/Header/header" import Main, {MainProps} from "@/app/components/Main/main" import "./main" export default function Index(): React.JSX.Element { return ( <div id="root"> <Header/> <Main prop={ new MainProps( "Sum all numbers till the given one", [ TaskContent({}), ], "article", ) }/> </div> ); }
解决方案
思路1:精准限定MDX组件类型(推荐)
这种思路让contentStack直接接受MDX组件本身,而非渲染后的JSX元素,更符合React组件的使用规范:
- 从
@mdx-js/react导入MDX组件的官方类型:
import type { MDXContent } from '@mdx-js/react';
- 定义专属的MDX组件类型(语义更清晰,可选):
// MDX组件本质是接受任意props的React函数组件 type MDXComponent = MDXContent;
- 修改
MainProps中contentStack的类型:
export class MainProps { constructor( public title: string, public contentStack: MDXComponent[] = [], // 替换为MDXComponent数组 public sectionOrArticle: "section" | "article" = "section", ) { } }
- 调整Main组件的渲染逻辑,直接在内部调用MDX组件:
export default function Main(props: { prop: MainProps }): React.JSX.Element { // 修正数组空值判断,用length更准确 if (props.prop.contentStack.length === 0) { return ( <main className={styles.main}> <h2>{props.prop.title}</h2> </main> ) } return ( <main className={styles.main}> <h2>{props.prop.title}</h2> { props.prop.sectionOrArticle !== "article" ? props.prop.contentStack.map((MdxComponent, index) => ( // 用索引做key更稳妥,避免indexOf导致的重复key问题 <section key={index}> <MdxComponent /> </section> )) : props.prop.contentStack.map((MdxComponent, index) => ( <article key={index}> <MdxComponent /> </article> )) } </main> ) }
- 调整使用示例,直接传入MDX组件而非调用后的元素:
export default function Index(): React.JSX.Element { return ( <div id="root"> <Header/> <Main prop={ new MainProps( "Sum all numbers till the given one", [TaskContent], // 直接传递MDX组件 "article", ) }/> </div> ); }
思路2:限定MDX渲染后的JSX元素(品牌类型)
如果坚持要传入渲染后的JSX元素,且需要区分普通JSX和MDX生成的元素,可以用品牌类型标记MDX元素:
- 定义带有品牌标识的MDX元素类型:
// 给普通JSX.Element添加专属标识,区分MDX生成的元素 type MDXElement = React.JSX.Element & { __brand: 'MDX' };
- 创建辅助函数,确保MDX组件返回的元素带有品牌标识:
// 辅助函数:调用MDX组件并返回标记后的MDXElement function renderMDX<T extends Record<string, unknown>>( mdxComponent: React.ComponentType<T>, props: T ): MDXElement { return <mdxComponent {...props} /> as MDXElement; }
- 修改
MainProps的contentStack类型为MDXElement[]:
export class MainProps { constructor( public title: string, public contentStack: MDXElement[] = [], // 替换为MDXElement数组 public sectionOrArticle: "section" | "article" = "section", ) { } }
- 在使用示例中用辅助函数包裹MDX组件的调用:
export default function Index(): React.JSX.Element { return ( <div id="root"> <Header/> <Main prop={ new MainProps( "Sum all numbers till the given one", [renderMDX(TaskContent, {})], // 用辅助函数生成MDXElement "article", ) }/> </div> ); }
补充提示
- 确保已安装必要依赖:
@mdx-js/react(MDX核心依赖)和@types/mdx(TypeScript类型支持)。 - 第一种思路更简洁易维护,建议优先采用,它直接利用MDX官方类型定义,避免额外的类型断言逻辑。
内容的提问来源于stack exchange,提问作者greg pinakapoging nilalang sa
相关产品推荐
相关产品推荐

