【问题标题】:How to type node-postgres async query functions in TypeScript?如何在 TypeScript 中键入 node-postgres 异步查询函数?
【发布时间】:2020-02-23 13:01:22
【问题描述】:

我对 TypeScript 相当陌生,并开始将我现有的服务器从 ES6 转换为 TypeScript。我有点迷茫,想弄清楚如何为异步函数声明类型。这是来自 ES6 代码的存根:

// db.js
import { Pool } from 'pg';

const pool = new Pool({
  connectionString: 'process.env.DB_CONNECTION',
});

export default {

  query(text, params) {
    return new Promise((resolve, reject) => {
      try {
        const result = pool.query(text, params);
        return resolve(result);
      } catch (error) {
        return reject(error);
      }
    });
  },
};

// controller for a table
const Table = {
  getOne: async (id) => {
    return await db.query('SELECT * FROM table WHERE id=$1', [id]);
  },
}

这很好用,可以通过消耗 try/catch 块中的部分来处理,无论查询返回结果还是错误,它都可以工作。现在我应该如何在打字稿中输入这些?我试过这样做:

import { Pool } from 'pg';

const pool = new Pool({
  connectionString: 'process.env.DB_CONNECTION',
});

export default {

  query(text: string, params: any[]) {
    return new Promise((resolve, reject) => {
      try {
        const result = pool.query(text, params);
        return resolve(result);
      } catch (error) {
        return reject(error);
      }
    });
  },
};

// controller
import { QueryResult } from 'pg';

const Table = {
  getOne: async (id: string) => {
    return await db.query('SELECT * FROM table WHERE id=$1', [id]) as QueryResult;
  },
}

现在,这可以编译,但有几件事我没有得到。首先,总是将这些返回类型转换为“as”是非常多余的。我不应该像getOne: async (id: string): Promise<QueryResult> => {...} 这样以某种方式声明返回类型吗?那么,如果 promise 被拒绝,会发生什么?那不再是 QueryResult 类型了。我试图阅读有关 node-postgres 和 TypeScript 函数类型声明的文档,但我一无所获。我应该怎么做这些?或许我也应该开始学习声明文件了。

【问题讨论】:

    标签: typescript async-await typing node-postgres


    【解决方案1】:

    异步函数隐式返回承诺

    示例:

    // Declare async function
    async function getRandomNumberAsync(max: number): Promise<number> {
      return Math.floor(Math.random() * Math.floor(max));
    }
    
    // Call it (errors are handled with a try/catch)
    try {
      const result = await getRandomNumberAsync(100);
      console.log(result);
    } catch (e) {
      console.error("something went wrong");
    }
    
    

    async/await 只是语法糖(在幕后,async/await 使用 Promises)。这段代码与上面的代码基本等价

    function getRandomNumberAsync(max: number): Promise<number> {
      return Promise.resolve(Math.floor(Math.random() * Math.floor(max)));
    }
    
    getRandomNumberAsync(100).then(result => {
      console.log(result);
    }).catch(e => {
      console.error("something went wrong");
    })
    

    我可以看到,在您的代码中,您使用的是 return await,这是多余的。甚至还有一个eslint rule 来防止这种情况发生

    你的代码应该是这样的

    const Table = {
      getOne: async (id: string): Promise<QueryResult> => {
        return db.query('SELECT * FROM table WHERE id=$1', [id]);
      },
    }
    
    // "getOne" should be called like this
    try {
      const result = await Table.getOne("YOUR_ID");
      // handle result
    } catch (e) {
      // handle error
    }
    

    除非你想处理getOne中的query错误

    它应该看起来像这样

    const Table = {
      getOne: async (id: string): Promise<QueryResult | string> => {
        try {
          return await db.query("SELECT * FROM table WHERE id=$1", [id]);
        } catch (e) {
          return "something went wrong";
        }
      },
    }
    

    【讨论】:

    • 非常感谢您的全面回答。我会稍微消化一下,可能很快就会接受。另外关于 await 的冗余使用,我知道它是多余的,但我用它来提醒人们,有一个承诺会返回给调用该函数的人。我不知道这在某些情况下是否会出现问题,但至少到目前为止它已经奏效了。不过我会尝试改掉这个习惯,因为我认为这可能不是一个好的编码习惯。
    • 将查询作为承诺返回似乎是一个优雅的解决方案。但是,如果我决定解析函数内部的 Promise 并返回解析结果,TS 仍然要求我将返回类型声明为 Promise<...>。为什么?也许我应该为此写一个全新的问题。
    猜你喜欢
    • 2021-02-10
    • 2018-10-23
    • 1970-01-01
    • 1970-01-01
    • 2020-04-28
    • 2020-08-24
    • 2015-02-20
    • 1970-01-01
    • 2022-11-29
    相关资源
    最近更新 更多