Using TypeScript, how do I strongly type mysql query results
// the function should return a Promise that resolves to
{ uid: number, uname: string }
// but typeof rows is
{ rows: { uid: number, uname: string } }
Executing the example, the result I get is something like:
[ TextRow { uid: 1, uname: 'foo', email: '[email protected]' } ]
So pool.query is returning an array with an array of IUser as first element.
Returning multiple users:
class UserController {
// returns all users
public async getUsers(): Promise<Array<IUser>> {
const [rows]: [Array<IUser>] = await pool.query(
"SELECT * FROM `user`", []);
return rows; // rows is Array<IUser> so it matches the promise type
}
}
Returning a specific user:
class UserController {
public async getUser(id: number): Promise<IUser> { // Note the
const [rows]: [Array<IUser>] =
await pool.query("SELECT * FROM `user` WHERE `email` = ?",
["[email protected]"]);
// If email is unique as it would be expected it will
// return a single value inside an array
// rows is still Array<IUser>
return rows[0]; // rows[0] is an IUser
}
}
Using [email protected], [email protected], @types/mysql2
The interface must extend RowDataPacket:
interface IUser extends RowDataPacket {
ssid: string
}
From there you can pass in the type:
const [rows]: [IUser[], FieldPacket[]] = await connection.query<IUser[]>("SELECT ssid FROM user", [])
or simply
const [rows] = await connection.query<IUser[]>("SELECT ssid FROM user", [])
Using pool.query<type>
was not enough for me when trying to set variables that were going to be used later because the datatype RowDataPacket
was still infringing on my types...
I ended up creating a wrapper for the pool
's query
function. Looks like this:
type Row = import("mysql2").RowDataPacket
type Ok = import("mysql2").OkPacket
type dbDefaults = Row[] | Row[][] | Ok[] | Ok
type dbQuery<T> = T & dbDefaults
export const db = {
query: async <T>(query: string, params?: Array<any>): Promise<[T, any]> => {
return pool.promise().query<dbQuery<T>>(query, params)
},
}
This allows me to use the query
function in other parts of the project similar to other answers as
let result = await db.query<desiredType>("SELECT", [optionalArgs])
but it strips away the type information for RowDataPacket, etc...