在TypeScript与Next.js中无法修改MDX导出类型的求助
问题
我开发了一个自定义插件,用于将MDX文件中的frontmatter转换为名为frontMatter的常量导出。例如a.mdx文件:
--- title: "Some Title" --- # Content
在Next.js页面中直接导入时,编译阶段会被转换为:
# Content export const frontMatter = { title: "Some Title" }
因此我在TypeScript + Next.js的页面文件中这样导入:
import AComponent, { frontMatter } from "a.mdx"
frontMatter的功能完全正常,但TypeScript编译器无法识别这个自定义导出——除非在MDX文件中显式写出该导出。我尝试声明模块,也确认tsconfig已经包含了类型定义文件,当前的模块声明如下:
declare module '*.mdx' { import { MDXProps } from 'mdx/types' const MDXComponent: (props: MDXProps) => JSX.Element const frontMatter: { [key: string]: any } export { frontMatter } export default MDXComponent }
但这个声明完全不起作用。不过我做了个测试:在同一个类型文件中声明如下模块时,导入是正常的:
declare module '*.myFile' { export const value }
我收到的具体错误提示是:
Module '"index.mdx"' has no exported member 'frontMatter'. Did you mean to use 'import frontMatter from "index.mdx"' instead?
我推测应该是有其他内容覆盖了MDX的类型定义,无论怎么调整自定义声明都无效。我的tsconfig.json配置如下:
{ "compilerOptions": { "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": true, "noEmit": true, "esModuleInterop": true, "module": "esnext", "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, "jsx": "preserve", "incremental": true, "plugins": [ { "name": "next" } ], "paths": { ... Some remappings here } }, "include": [ "next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.mdx", ".next/types/**/*.ts", "THE MODULE DECLARATION FILE" ], "exclude": ["node_modules"] }
解决方案
1. 排查冲突的类型定义
Next.js或MDX官方可能自带了*.mdx的类型声明,导致你的自定义声明被覆盖:
- 检查
node_modules下的@types/mdx、next/dist/types目录,看看是否存在MDX相关的默认类型定义。 - 将自定义类型声明文件命名为
mdx.d.ts,放在项目根目录或src/types文件夹下,确保它在TypeScript的扫描路径内。
2. 修正模块声明写法
调整声明结构,确保类型导出符合TypeScript规范:
declare module '*.mdx' { import type { MDXProps } from 'mdx/types'; const Component: (props: MDXProps) => JSX.Element; export const frontMatter: Record<string, unknown>; export default Component; }
这里用type导入避免运行时冗余引用,同时用Record<string, unknown>替代{ [key: string]: any },类型更严谨。
3. 调整tsconfig配置
- 确保
include数组中的类型声明文件路径正确,比如如果放在src/types/下,就写src/types/**/*.d.ts,不要硬编码文件名。 - 在
compilerOptions中添加typeRoots,让TypeScript优先加载自定义类型:
"compilerOptions": { // 其他配置保持不变 "typeRoots": ["./src/types", "./node_modules/@types"] }
这样自定义类型会比node_modules里的类型更早被加载,避免被覆盖。
4. 清除Next.js缓存
缓存可能导致类型未更新,执行以下命令清理后重新构建:
rm -rf .next npm run build
内容的提问来源于stack exchange,提问作者cpix
相关产品推荐
相关产品推荐

