I got an error when I change the syntax from require
, CommonJS, to import
, ES Module.
I tried to create a todo-app with Node.js, TypeScript, MySQL.
First, I wrote the following code.
// db.ts
export {};
const mysql = require('mysql2');
const pool = mysql.createPool({
host: 'localhost',
user: 'user',
password: 'password',
database: 'db',
});
module.exports = pool;
//index.ts
import express from 'express';
import { Express, Request, Response } from 'express';
import { QueryError, RowDataPacket } from 'mysql2';
const pool = require('./db');
const app: Express = express();
app.get("/todos", async (req: Request, res: Response) => {
await pool.promise().query(
'SELECT * FROM todo'
)
.then((rows: RowDataPacket[]) => {
res.json(rows[0]);
})
.catch((error: QueryError) => {
throw error;
})
});
These codes work well. There is no error.
However, using import
instead of require
brings me an error.
//db.ts
import { createPool } from 'mysql2';
export const pool = createPool({
host: 'localhost',
user: 'user',
password: 'password',
database: 'db',
});
//index.ts
import express from 'express';
import { Express, Request, Response } from 'express';
import { QueryError, RowDataPacket } from 'mysql2';
import { pool } from '.db';
const app: Express = express();
app.get("/todos", async (req: Request, res: Response) => {
await pool.promise().query(
'SELECT * FROM todo'
)
.then((rows: RowDataPacket[]) => {
res.json(rows[0]);
})
.catch((error: QueryError) => {
throw error;
})
});
I got a following error.
Argument of type '(rows: RowDataPacket[]) => void' is not assignable to parameter of type '(value: [RowDataPacket[] | RowDataPacket[][] | OkPacket | OkPacket[] | ResultSetHeader, FieldPacket[]]) => void | PromiseLike<...>'.
Types of parameters 'rows' and 'value' are incompatible.
Type '[RowDataPacket[] | RowDataPacket[][] | OkPacket | OkPacket[] | ResultSetHeader, FieldPacket[]]' is not assignable to type 'RowDataPacket[]'.
Type 'RowDataPacket[] | RowDataPacket[][] | OkPacket | OkPacket[] | ResultSetHeader | FieldPacket[]' is not assignable to type 'RowDataPacket'.
Type 'RowDataPacket[]' is not assignable to type 'RowDataPacket'.
The types of 'constructor.name' are incompatible between these types.
Type 'string' is not assignable to type '"RowDataPacket"'.
Why I had this error?
I think using require
or import
gives same functionality, so I'm very confused.
extra info
tsconfig.json
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
}
}
CodePudding user response:
Simply specifying the exact type of the result set you're getting helps (.query(...)
to .query<RowDataPacket[]>(...)
).
(I also changed your mixing-and-matching of async
with .then
to an await
.)
app.get("/todos", async (req: Request, res: Response) => {
const resp = await pool.promise().query<RowDataPacket[]>(
'SELECT * FROM todo'
);
res.json(resp[0]);
});
I'd guess the types for mysql2
were quite loose in the require
case, so you were never truly validating them.
For completeness' sake, this is the full single-file test program that successfully typechecks.
import express from 'express';
import { Express, Request, Response } from 'express';
import { RowDataPacket, createPool } from 'mysql2';
const pool = createPool({
host: 'localhost',
user: 'user',
password: 'password',
database: 'db',
});
const app: Express = express();
app.get("/todos", async (req: Request, res: Response) => {
const resp = await pool.promise().query<RowDataPacket[]>(
'SELECT * FROM todo'
);
res.json(resp[0]);
});