TypeScript中mysql2查询结果无法赋值给IUser[]的问题解决
问题描述
我编写了如下Users类:
class Users { static async findAll(req: Request, res: Response, next: NextFunction) : Promise<IUser[]> { const rows = await Pools.execute("SELECT * FROM users" ) .then((rows) => { return rows[0]; }) .catch(err => console.log(err)); next(); return rows; } }
但在return rows;处出现错误:
Type 'void | RowDataPacket[] | RowDataPacket[][] | OkPacket | OkPacket[] | ResultSetHeader' is not assignable to type 'IUser[]'.
Type 'void' is not assignable to type 'IUser[]'.
IUser接口定义如下:
import { RowDataPacket } from "mysql2" interface IUser extends RowDataPacket { id?: number; email: string; password: string; username: string; admin: boolean; created_at: Date; } export {IUser};
已知rows[0]的实际数据结构如下:
[ { "id": 1, "email": "admin@u.com", "password": "12345", "username": "admin@u.com", "admin": 1, "created_at": "2023-01-06T02:31:14.000Z" }, { "id": 2, "email": "u@u.com", "password": "12345", "username": "u@u.com", "admin": 0, "created_at": "2023-01-06T03:08:20.000Z" } ]
请问该错误产生的原因是什么,如何修复?
错误原因
- catch块无返回值导致类型混入void:你在
Pools.execute()的catch回调里只打印错误,没有返回任何值,这会让Promise的返回类型包含void,但函数声明必须返回Promise<IUser[]>,类型不兼容。 - TypeScript无法自动推断返回类型:mysql2的
execute()返回的是多种类型的联合(比如RowDataPacket、OkPacket),TS无法自动识别rows[0]就是你定义的IUser[],需要手动断言类型。 - 字段类型不匹配:数据库中
admin字段存储的是数字1/0,但IUser接口里定义的是boolean类型,这也会触发类型校验失败。
修复方案
1. 重构错误处理,避免void类型
把Promise链的catch换成try/catch结构,这样错误时要么抛出错误让后续中间件处理,要么返回符合类型的默认值,不会让rows变量混入void类型。
2. 显式类型断言+字段类型转换
将查询结果断言为RowDataPacket[],再把admin字段从数字转换为布尔值,最后断言为IUser[]。
修复后的完整代码
class Users { static async findAll(req: Request, res: Response, next: NextFunction): Promise<IUser[]> { try { // 解构获取查询结果,替代rows[0]的写法更直观 const [rows] = await Pools.execute("SELECT * FROM users"); // 转换admin字段类型,并断言为IUser数组 const users = (rows as RowDataPacket[]).map(row => ({ ...row, admin: row.admin === 1, created_at: new Date(row.created_at) })) as IUser[]; next(); return users; } catch (err) { console.log(err); // 抛出错误让中间件处理,或者返回空数组[] throw err; } } }
可选优化:用mysql2泛型简化类型断言
mysql2的execute方法支持泛型参数,可以直接指定返回的行类型,减少手动断言的代码:
class Users { static async findAll(req: Request, res: Response, next: NextFunction): Promise<IUser[]> { try { // 通过泛型指定返回的行类型为RowDataPacket[] const [rows] = await Pools.execute<RowDataPacket[]>("SELECT * FROM users"); const users = rows.map(row => ({ ...row, admin: row.admin === 1, created_at: new Date(row.created_at) })) as IUser[]; next(); return users; } catch (err) { console.log(err); throw err; } } }
内容的提问来源于stack exchange,提问作者best_of_man
相关产品推荐
相关产品推荐

