mysql2模块中的OkPacket类型上不存在'length'属性

7
我有类似这样的代码 - 非常简单,只是为了展示情况。
this.getCode = (code: string): Promise<codeObject | false> => {
        return new Promise((resolve, reject) => {
            pool.query('SELECT * FROM ?? WHERE code = ?', [TABLE, code], function (err, result) {
                if (err) {
                    return reject(err);
                }

                if (result.length === 0) {
                    return resolve(false);
                }
            });
        });
    };

问题出在if (result.length === 0) {这一行,错误信息为error TS2339: Property 'length' does not exist on type 'RowDataPacket[] | RowDataPacket[][] | OkPacket | OkPacket[]'.

我找不到任何重新定义OkPacket的方法,至少要有length?: number就足以忽略此错误(大多数选择都不会得到OkPackets,而且我不想在每个选择上检查类型,如果我知道它不是OkPacket时,我不想这样做)...


[TABLE] 是什么? - random
它的 const TABLE: string = table_name; - Seti
你对类型检查有什么反对意见?看起来这是处理这个问题最直接的方式。 - etarhan
2
在处理select的每个函数(大多数)中,我需要找出哪个结果不是OkPacket,但当我无法获取该类以进行instanceof检查时,我不想只检查构造函数名称是否为“OkPacket”,因为这真的很糟糕。 - Seti
5个回答

8

我曾经遇到相似的问题,并且能够修复TypeScript警告: "Property 'length' does not exist on type 'OkPacket'",方法是检查查询结果是否为数组。对我来说,这比将结果转换为字符串再使用JSON.stringify()要简单得多。

对于上面的原始示例,我会将result.length的比较更改为以下内容:

if (Array.isArray(result) && result.length === 0) {
   return resolve(false);
}

谢谢!这个解决方案对我也起作用了。 - Alex_Lima84

1

我也找不到一个合适的处理方法,所以最终采用了这个解决方案来解决我的类似情况:

const [rows,] = await connection.execute("SELECT id FROM users WHERE email = ?", [profile.email]);
if ((rows as any).length === 1) {
   return (rows as any)[0].id;
}
logger.error("Unexpected query response", rows);
throw Error("This code should never be executed");

您也可以使用用户定义类型守卫。像这样:
const isRowDataPacket = (rows: RowDataPacket[] | RowDataPacket[][] | OkPacket | OkPacket[] | ResultSetHeader): rows is RowDataPacket[] | RowDataPacket[][] => {
    return (rows as RowDataPacket[] | RowDataPacket[][]).length !== undefined
}

但是您仍需要进一步进行类型转换以正确解释每一行:
const [rows,] = await connection.execute("SELECT id FROM users WHERE email = ?", [profile.email]);
if (isRowDataPacket(rows) && rows.length === 1) {
    return (rows[0] as { id: string }).id;
}

我最终检查了那个该死的东西 - 只是像任何人一样进行了检查。 - Seti

0

我也不喜欢这个设计选择,但我通常使用:

const [rows, fields] = await conn.execute(QUERY_STRING) as any
console.log(rows.length)

0

我也讨厌这个错误。 这是我的解决方法:

const [rows] = await db.query(`mySqlHere`);
let tempResult: any = rows;

console.log(tempResult.length); // OK

1
但这会将tempResult作为“any”类型,这对于TypeScript来说并不是更好的选择。 - Seti
是的,我知道,但我找不到让那个警告消失的方法。还有很多关于TypeScript需要学习的地方。 - Javohir Mirzo Fazliddinov
在我看来,它仍然比返回无法使用的类型要好。如果你的库是无用的,但 typings 很棒... 那就很傻。 - Romain Bruckert

0

对于我的用例,mapOkPacket中没有定义,因为我需要以下内容

function (error, results, fields) {

            const data = results.map((item: any) => {
                //... do stuffs..
                return {
                    name: item.name,
                    username: item.username,
                    image: item.image,
                    bio: item.bio,
                    url: item.url,
                }
            })
            resolve([results, fields]);
}


为了摆脱这个错误,我最终检查了结果对象中是否存在map,如果不存在就提前返回(仅仅使用reject()无法修复错误)。修改后的代码如下所示。
function (error, results, fields) {
            if(!('map' in results)) {
                reject(results);
                return;
            }
            const data = results.map((item: any) => {
                // ...do stuff...
                return {
                    name: item.name,
                    username: item.username,
                    image: item.image,
                    bio: item.bio,
                    url: item.url,
                }
            })
            resolve([results, fields]);
}

对于您的情况,您可以检查例如length,并在其不存在时提前返回。
if(!('length' in results)) {
     reject(results);
     return;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接