我是TypeScript新手,正在尝试将现有的JS (react)项目慢慢迁移到TypeScript中。
我有一个执行查询的函数:
/**
* Run a Query against the currently connected database
* @param {String} sql Query to run
* @param {Object[]} Array of objects to be used in the prepared statement
* @returns {Promise<Object[]>} Promise resolving after query is done. Returns an array of arrays with the result.
*/
const query = (sql, params) => {
//Database stuff
}
我在很多地方调用这个:
const result = await query('SELECT count(*) as cnt from Table id=?',[2]')
return result[0].cnt
最后一行出现错误,因为字段"cnt"是未知的。如何最好地解决这个问题?返回类型始终是Object[],但对象的内容取决于查询。
有什么建议如何最好地移动这个代码到TS?
这是必须告诉类型系统所期望的内容的地方之一。当然,您在这样做时必须非常小心,以确保您向类型系统提供了准确的信息。通常,您希望尽可能早地这样做,以便构建在其上的更复杂的代码可以依赖于这些类型。
所以答案分为两部分:
-
如何输入
query
,和 -
避免直接使用
query
的建议
首先,你可以让query
成为一个泛型函数,给它一个泛型类型参数,告诉它返回什么类型的对象:
/**
* Run a Query against the currently connected database
* @param {string} sql Query to run
* @param {any[]} Array of objects to be used in the prepared statement
* @returns {Promise<ResultType[]>} Promise resolving after query is done. Returns an array of arrays with the result.
*/
const query = <ResultType extends object>(sql: string, params: any[]): Promise<ResultType[]> => {
// −−−−−−−−−−−^^^^^^^^^^^^^^^^^^^^^^^^^^^−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^^^^^^^^^^^^^^^^^^^^^
//Database stuff
};
然后你可以这样使用:
const result = await query<{cnt: number}>('SELECT count(*) as cnt from Table id=?', [2]);
// −−−−−−−−−−−−−−−−−−−−−−−−^^^^^^^^^^^^^
return result[0].cnt;
但这就是第2条的用武之地:我不会这样做,除非在函数中只定义一次它的工作是告诉您匹配的行数:
async function getCountFromExampleTable(id: number): Promise<number> {
const result = await query<{cnt: number}>('SELECT count(*) as cnt from Table id=?', [id]);
return result[0].cnt;
}
很容易看到getCountFromExampleTable
并知道我们给出的类型参数({cnt: number}
)是正确的。然后,任何需要这样做的代码都可以重用getCountFromExampleTable
,而不必提供该类型参数(可能会出错)。
您可能希望getCountFromExampleTable
更通用,可能接受表名和参数,但是您明白了。(如果是这样,请务必测试表名,以确保它不会被用作SQL注入攻击的一部分,并继续使用已准备好的语句。)
操场上联系
必须使用泛型
const query = <T>(sql: string, params: Object[]): T[] => {
return []
}
但是函数可以返回空数组。在本例中,您可以像这样检查cnt
属性
const result = await query('SELECT count(*) as cnt from Table id=?',[2])
return result[0]?.cnt