node-mysql2
node-mysql2 copied to clipboard
Element implicitly has an 'any' type because expression of type '0' can't be used to index type 'RowDataPacket[] | RowDataPacket[][] | OkPacket | OkPacket[] | ResultSetHeader'. Property '0' does not exist on type 'RowDataPacket[] | RowDataPacket[][] | OkPacket | OkPacket[] | ResultSetHeader'. When trying to access any index of the result parameter in the callback
Hi there so I have this code
static async getById(id: string): Promise<Business> {
return new Promise((resolve, reject) => {
connection.execute(
"SELECT * FROM business WHERE ID = ?;",
[id],
(err, result) => {
if (err) reject(err);
const { id, name, email, password }: {id: string, name: string, email: string, password: string} = result[0]; //it complains here
resolve({
id,
name,
email,
password,
});
}
);
});
}
And I have typescript giving me this error:
Element implicitly has an 'any' type because expression of type '0' can't be used to index type 'RowDataPacket[] | RowDataPacket[][] | OkPacket | OkPacket[] | ResultSetHeader'.
Property '0' does not exist on type 'RowDataPacket[] | RowDataPacket[][] | OkPacket | OkPacket[] | ResultSetHeader'.ts(7053)
And I'm really not sure what to be doing here because I can't change return type of result
+1, also an issue here got around it by typecasting, but I don't know the library/mysql well so it's not ideal.
const [matches] = await db.Connection.query(
"SELECT `Discord UID` FROM `Information` WHERE `Staff Code` = ? OR `Discord UID` = ? OR `Roblox UID` = ? OR `Email`= ?",
[`${staffInfo.department}-${staffInfo.staffid}`, staffInfo.user.id, userId, staffInfo.email],
);
console.log((matches as RowDataPacket[])[0]);
this is with "mysql2/promise"
I’m using .execute<RowDataPacket[]>(...) for single-statement selects. Similarly, multi-statement selects would have .execute<RowDataPacket[][]>(...).
I don’t know whether the right type for inserts, updates, creates etc. is ResultSetHeader (which I’m getting in practice) or OkPacket | ResultSetHeader, though.
@astiob I'm not an expert in TS but your comment looks right from the protocol point of view: result of query / execute can be
- array of rows ( single select statement )
OkPacket | ResultSetHeader( single insert / delete / update / set variable statement ) ( I'm actually quite confused, they look nearly identical. Need to investigate why we need two )- array of (1|2) in case of multiple statements
^ not just multiple statements in a single query "select 1; select 2", a prepared statement can also return multiple tables - see https://github.com/sidorares/node-mysql2/blob/dbb344e89a1cc8bb457b24e67b07cdb3013fe844/test/integration/connection/test-binary-multiple-results.js#L77-L100
Add this if else condition to handle the typescript
if(Array.isArray(result)){
//your thing
} else {
//res send status 500
}
Hi @destroyer22719, complementing @astiob's answer, you can do it by:
- Extending
mysql.RowDataPacket - Using
asfrom TypeScript
Some practical examples:
See the comments
Extending mysql.RowDataPacket (A)
import mysql from 'mysql2';
/** Typing Business and extending the `mysql.RowDataPacket` */
interface Business extends mysql.RowDataPacket {
id: number;
name: string;
email: string;
password: string;
}
const access: mysql.PoolOptions = {};
const query = 'SELECT * FROM business WHERE ID = ?;';
const params = [1];
mysql.createPool(access).getConnection((_err, connection) => {
/* Using the Business interface */
connection.execute<Business[]>(query, params, (_err, result) => {
const { id, name, email, password } = result[0];
console.log({
id,
name,
email,
password,
});
});
});
Extending mysql.RowDataPacket (B)
import mysql from 'mysql2';
/** Typing Business and extending the `mysql.RowDataPacket` */
interface Business extends mysql.RowDataPacket {
id: number;
name: string;
email: string;
password: string;
}
const access: mysql.PoolOptions = {};
const query = 'SELECT * FROM business WHERE ID = ?;';
const params = [1];
mysql.createPool(access).getConnection((_err, connection) => {
/* Using the Business interface directly in `result` */
connection.execute(query, params, (_err, result: Business[]) => {
const { id, name, email, password } = result[0];
console.log({
id,
name,
email,
password,
});
});
});
Using as from TypeScript (A)
import mysql from 'mysql2';
/** Typing Business */
interface Business {
id: number;
name: string;
email: string;
password: string;
}
const access: mysql.PoolOptions = {};
const query = 'SELECT * FROM business WHERE ID = ?;';
const params = [1];
mysql.createPool(access).getConnection((_err, connection) => {
connection.execute(query, params, (_err, result) => {
/* Using the Business interface from TypeScript `as` */
const business = result as Business[];
const { id, name, email, password } = business[0];
console.log({
id,
name,
email,
password,
});
});
});
Using as from TypeScript (B)
import mysql from 'mysql2';
/** Typing Business */
interface Business {
id: number;
name: string;
email: string;
password: string;
}
const access: mysql.PoolOptions = {};
const query = 'SELECT * FROM business WHERE ID = ?;';
const params = [1];
mysql.createPool(access).getConnection((_err, connection) => {
connection.execute(query, params, (_err, result) => {
/* Using the Business interface from TypeScript `as` directly in `result` */
const { id, name, email, password } = (result as Business[])[0];
console.log({
id,
name,
email,
password,
});
});
});
@astiob I'm not an expert in TS but your comment looks right from the protocol point of view: result of query / execute can be
- array of rows ( single select statement )
OkPacket | ResultSetHeader( single insert / delete / update / set variable statement ) ( I'm actually quite confused, they look nearly identical. Need to investigate why we need two )- array of (1|2) in case of multiple statements
@sidorares, after reviewing all TypeScript Issues, I noticed that there are many questions, mostly about the use of types in execute and query.
I think it's good to have a "TypeScript Examples" documentation like in documentation/en/Examples.md.
Yes, definitely. Even just copying your previous comment to "TypeScript Examples" section would be of great value
You can follow this example to see how to extend the RowDataPacket:
Also:
- Extending and using Interfaces with
RowDataPacketandrowAsArray - Extending and using Interfaces with
RowDataPacketandmultipleStatements - Extending and using Interfaces with
RowDataPacket,rowAsArrayandmultipleStatements
And finally, you can follow the documentation: documentation/en/TypeScript-Examples.md#type-specification
I'm closing this Issue, but feel free to ask anything 🙋🏻♂️