NextJS is throwing an error when trying to use a .mdx file with Typescript

Everything is working fine for rendering components on the website, but TypeScript is showing an error when importing mdx files.

The TypeScript error message reads: Cannot find module '@/articles/good.mdx' or its corresponding type declarations.

I've come across numerous comments on Stack Overflow, but none of the solutions have resolved this issue. I even tried installing @mdx-js/mdx, but it didn't work either.

import React from "react";

import Layout from "@/components/Layout/index";
import Good from "@/articles/good.mdx"; // This line shows a TypeScript error

const index = () => {
  return (
    <Layout>
      <Good />
    </Layout>
  );
};

export default index;

Package.json (some entries removed for brevity)

{
  "dependencies": {
    "@next/mdx": "^10.2.0",
    "@types/react-transition-group": "^4.4.1",
    "next": "10.1.3",
    "next-seo": "^4.24.0",
    "react": "17.0.2",
    "react-dom": "17.0.2",
    "react-query": "^3.13.11",
    "react-transition-group": "^4.4.1"
  },
  "devDependencies": {
    "@mdx-js/loader": "^1.6.22",
    "@types/node": "^15.0.1",
    "@types/react": "^17.0.4",
    "@types/webpack-env": "^1.16.0",
    "autoprefixer": "^10.2.5",
    "typescript": "^4.2.4"
  }
}

tsconfig.json (some entries removed for brevity)

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "types": [
      "node",
      "webpack-env"
     ]
  },
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx",
    "**/*.mdx",
  ],
  "exclude": [
    "node_modules"
  ]
}

Answer №1

mdxjs has implemented a new feature for types

Use the following command to install types for mdx: npm install @types/mdx --save-dev

Answer №2

To fix this issue, you can create a file named mdx.d.ts. Place it in either the root directory or a folder called types within the root of your project. Copy and paste the following code into this file:

declare module '*.mdx' {
  let MDXComponent: (props: any) => JSX.Element;
  export default MDXComponent;
}

This code sets up global types for files with the extension .mdx, informing typescript that default imports from these files will return (props: any) => JSX.Element. This makes it safe to use these components in your .tsx files as <YourMdxComponent />.

Answer №3

For an easier way, consider installing types with yarn add @types/mdx. Then, include those types in your tsconfig.ts

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "types": [
      "node",
      "webpack-env", 
      "mdx"
     ]
  },
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx",
    "**/*.mdx",
  ],
  "exclude": [
    "node_modules"
  ]
}

If you try to reexport a custom component from an mdx file using:

import YourMdxContent, { SomeComponent } from './YourMdxFile.mdx'

You may encounter the following error message:

Module '"*.mdx"' has no exported member 'SomeComponent'. Did you mean to use 'import SomeComponent from "*.mdx"' instead?

If this issue arises, you will need to declare the mdx module again:

declare module '*.mdx' {
  export function SomeComponent(): JSX.Element;
}

There is no necessity to redecalare MDXContent as it is already inherited from the types.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Playwright Vercel Error: Unable to launch browserType. The executable cannot be found at the specified directory

After testing my application on various local environments such as Windows, Linux, and macOS where it worked perfectly fine, I encountered an error when deploying my nextjs app on Vercel. browserType.launch: Executable doesn't exist at /home/sbx_user1 ...

What are the steps for implementing the ReactElement type?

After researching the combination of Typescript with React, I stumbled upon the type "ReactElement" and its definition is as follows: interface ReactElement<P = any, T extends string | JSXElementConstructor<any> = string | JSXElementConstructor< ...

Moving Configuration Files in NextJS

When working on a typical Next.js project, I often end up with several root-level configuration files: tsconfig.json next.config.js next-seo-config.ts .eslintrc etc... I am looking to tidy up my root directory by moving these files into their own separat ...

"Overcoming obstacles in managing the global state of a TypeScript preact app with React/Next signals

Hello, I recently attempted to implement a global app state in Preact following the instructions provided in this documentation. However, I kept encountering errors as this is my first time using useContext and I suspect that my configuration might be inco ...

The rendering of HTML is not supported by Next.js SSR

I'm a bit confused about how Next.js SSR works. On my index page, I've used getServerSideProps, so I expected the page to be prerendered as HTML. However, it seems to only render a single div, a JSON object, and the Next.js scripts, with the page ...

Tips for effectively sending data using slug.js in React.js

I'm a beginner in Next.js and I'm currently working on integrating the [slug.js] page. I'm wondering how to effectively manage and retrieve data for similar blogs in the sidebar. When it comes to blog details, I have successfully utilized "g ...

TypeScript: Type narrowing issue when deconstructing an array within a function

I am working with an object that has a const assertion: const foo = { bar: ['a', 'b'], } as const; My objective is to create a function that can update the bar array and accurately infer the new type. I have successfully achieved th ...

TypeScript - Issue with generic function's return type

There exists a feature in typescript known as ReturnType<TFunction> that enables one to deduce the return type of a specific function, like this function arrayOf(item: string): string[] { return [item] } Nevertheless, I am encountering difficulti ...

What is the best way to display data retrieved through an HTTP service using ngFor?

I was attempting to inject a service (contact.service.ts) into a component (contact-list.component). The service contains data on employees defined in contacts.ts. While I was able to successfully receive the data, I encountered difficulty in rendering it ...

Exploring Cypress: Iterating over a collection of elements

I have a small code snippet that retrieves an array of checkboxes or checkbox labels using cy.get in my Angular application. When looping through the array to click on each element and check the checkboxes, it works fine if the array contains only one elem ...

What could be the issue causing this indexed signature to fail?

I'm attempting to extract an object's values and use them as keys for the interface. Here is my approach: const obj = { a: 'foo', b: 'bar', } as const; type A<T extends object, K extends keyof T = keyof T> = { ...

Currently, ReactMarkdown is unable to support rendering capabilities

When using a markdown file to load data initially, I want to render images in a div tag and follow default behavior for paragraphs if no image is present. const customRenderers = { paragraph(paragraph) { const {node} = paragraph ...

Is it possible for the button text to switch from Farewell to Greetings after two clicks?

There seems to be a strange issue in my React TS project - I have to click the button twice to switch the text from "Goodbye" to "Hello", but not the other way around. Any ideas why? import { useState } from 'react' const ChangeTextButton = () ...

Troubleshooting Vuex Getters with Typescript

Currently, I am working on a project that utilizes Vuex and the Composition API. With typescript enabled, I have a component in which I need to retrieve a boolean value from a getter in my store module using the following code: const flag = computed(() =&g ...

Typescript enums causing Safari to display blank screen in Next.js

The website performs well on Chrome and Edge, but encounters difficulties on Safari for iOS. Although all the elements, styling, and scripts load properly, nothing appears on the screen. After spending countless hours debugging, I discovered that the pro ...

Having trouble displaying an image in the Image tag when using Next.js and Material UI

I'm encountering an issue while attempting to showcase images in my Next.js project with Material UI. Here is the code snippet I am using: <Box display="flex" alignItems="center"> <Image s ...

Technique in CSS/SASS to repair a div

Seeking a solution for fixing divs with text in CSS. I am aware of the background-attachment: fixed; property which creates a fancy effect. Is there a similar property to "fix" divs with text or how can this be achieved in Typescript? Your insight would be ...

Challenges Encountered with Server Operations in Next.js v14 - Issue with Cookie Modification

I am currently working on a project using Next.js v14 and I have run into an issue with Server Actions, specifically when attempting to modify cookies. Despite meticulously following the documentation and ensuring that my functions are classified as Server ...

Steps to resolve the 'Cannot assign value to userInfo$ property of [object Object] that only has getter' issue in Angular

I am currently in the process of building a web application using NGXS, and I'm encountering a specific error that I'm trying to troubleshoot. The issue arises when I attempt to fetch data from an API and display it within a column on the page. D ...