You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将Node.js+TypeScript项目从CommonJS的require语法改为ES Module的import语法时出现类型错误

Why Type Error Occurs When Switching from CommonJS to ES Modules in Node.js/TypeScript MySQL2 Todo App

Hey there! Let's break down why this type error popped up when you switched from require to import, and how to fix it quickly.

The Root Cause

When using pool.promise().query() from mysql2, the Promise resolves to a tuple (fixed-length array) containing two elements:

  1. The actual query result set (e.g., RowDataPacket[] for a SELECT query)
  2. Metadata about the query's fields (FieldPacket[])

In your CommonJS code, TypeScript's type checking for CommonJS modules was more lenient—it didn't catch that you were treating this tuple as a single RowDataPacket[]. When you switched to ES Modules with import, TypeScript enforces stricter type validation, which exposed this mismatch. The error message directly points to this: your callback expects a single result array, but it's receiving the full tuple of result + field data.

Fixing the Type Error

You have two clean solutions, depending on your preferred syntax style:

Option 1: Correct Tuple Destructuring in then

Update your callback to destructure the tuple and use the proper type annotation:

app.get("/todos", async (req: Request, res: Response) => {
  await pool.promise().query('SELECT * FROM todo')
    // Destructure the tuple and define correct types for both elements
    .then(([rows, fields]: [RowDataPacket[], FieldPacket[]]) => {
      res.json(rows); // `rows` is the actual array of todo items—no need for rows[0]!
    })
    .catch((error: QueryError) => {
      console.error(error);
      res.status(500).json({ error: error.message }); // Always return an error response instead of throwing
    });
});

Note: Your original code used rows[0], which was incorrect—rows itself is the full array of results from the SELECT query.

Option 2: Use async/await with Generic Type (Cleaner)

Since you're already using an async function, you can simplify the code by ditching then/catch and using mysql2's generic query method to explicitly define the result type:

app.get("/todos", async (req: Request, res: Response) => {
  try {
    // Use the generic to tell TypeScript the type of the result rows
    const [rows, fields] = await pool.promise().query<RowDataPacket[]>('SELECT * FROM todo');
    res.json(rows);
  } catch (error) {
    // Narrow the error type to QueryError for better type safety
    const queryError = error as QueryError;
    console.error(queryError);
    res.status(500).json({ error: queryError.message });
  }
});

Why CommonJS Didn't Throw This Error

TypeScript handles CommonJS modules differently—when you use module.exports = pool, the type inference is less strict compared to ES Module's export const pool. Your incorrect type annotation in the CommonJS code was essentially ignored, hiding the underlying type mismatch. Switching to ES Modules made TypeScript enforce proper type checking, which is actually a good thing—it helps you catch bugs early!

Your tsconfig.json is perfectly valid: setting module: commonjs while using ES Module syntax works smoothly thanks to esModuleInterop: true, which handles compatibility between the two module systems.

内容的提问来源于stack exchange,提问作者F.Yuya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 15:17:45