【问题标题】:How to properly deal with promisifyAll in typescript?如何正确处理 typescript 中的 promisifyAll?
【发布时间】:2016-08-02 11:08:21
【问题描述】:

考虑以下代码:

import redis = require('redis');  //Has ambient declaration from DT
import bluebird = require('bluebird');  //Has ambient declaration from DT

bluebird.promisifyAll((<any>redis).RedisClient.prototype);
bluebird.promisifyAll((<any>redis).Multi.prototype);

const client = redis.createClient();

client.getAsync('foo').then(function(res) {
    console.log(res);
});

getAsync 会出错,因为它是动态创建的,没有在任何.d.ts 文件中定义。那么处理这个问题的正确方法是什么?

此外,即使我为 redis 加载了 .d.ts 文件,我仍然需要将 redis 转换为 any 以用于 promisifyAll。否则会溢出错误:

Property 'RedisClient' does not exist on type 'typeof "redis"'

将其输入any 是唯一简单的方法吗?

【问题讨论】:

  • 你有没有找到解决这个问题的方法?我遇到了同样的问题...
  • @zam6ak 是的,通过使用声明合并。请参阅下面的答案。

标签: javascript typescript promise bluebird


【解决方案1】:

这个解决方案对我来说很好:

import { promisifyAll } from 'bluebird'; // import here works only if @types/bluebird is installed
import redis, { RedisClient, Multi } from 'redis'; // import here works only if @types/redis is installed

// Convert Redis client API to use promises, to make it usable with async/await syntax
const MultiAsync: any = promisifyAll(Multi.prototype);
const RedisClientAsync: any = promisifyAll(RedisClient.prototype);
const redisAsync = { ...redis, Multi: MultiAsync, RedisClient: RedisClientAsync };

const client: typeof RedisClientAsync = redisAsync.createClient();
// now you can use client async methods, i.e. client.getAsync, client.hgetAsync, client.hsetAsync, client.expireAsync...

【讨论】:

    【解决方案2】:

    另一种需要更少代码的方法是像这样扩展 Redis 对象:

    import { promisify } from 'util';
    import { ClientOpts, RedisClient } from 'redis';
    
    class AsyncRedis extends RedisClient {
      public readonly getAsync = promisify(this.get).bind(this);
      public readonly setAsync = promisify(this.set).bind(this);
      public readonly quitAsync = promisify(this.quit).bind(this);
      public readonly rpushAsync: (list: string, item: string) => Promise<number> = promisify(
        this.rpush
      ).bind(this);
      public readonly blpopAsync: (
        list: string,
        timeout: number
      ) => Promise<[string, string]> = promisify(this.blpop).bind(this);
      public readonly flushdbAsync = promisify(this.flushdb).bind(this);
    }
    

    请注意,并非所有方法签名都正确覆盖,因此您必须帮助 typescript 一点。

    现在您可以通过使用您的选项创建这个增强类来使用它,例如:

    new AsyncRedis({
      host: process.env.REDIS_HOST || '127.0.0.1',
      password: process.env.REDIS_PASSWORD || 'whatever',
     });
    

    【讨论】:

      【解决方案3】:

      只是添加到 Dave 的答案中,在我的需要中,我必须添加 Multi 以进行原子操作。

      declare module 'redis' {
          export interface RedisClient extends NodeJS.EventEmitter {
              execAsync(...args: any[]): Promise<any>;
              hgetallAsync(...args: any[]): Promise<any>;
              // add other methods here
          }
          export interface Multi extends Commands<Multi> {
              execAsync(...args: any[]): Promise<any>;
              // add other methods here
          }
      }
      
      

      【讨论】:

        【解决方案4】:

        我正在通过declaration merging setAsyncgetAsync 方法解决这个问题。我在自己的自定义.d.ts 文件中添加了以下代码。

        declare module "redis" {
        
            export interface RedisClient extends NodeJS.EventEmitter {
                setAsync(key:string, value:string): Promise<void>;
                getAsync(key:string): Promise<string>;
            }
        
        }
        

        【讨论】:

        • 这对于大型库是否可维护?如果你承诺一个有很多方法的库怎么办 - 你是否必须重新声明所有 *Async() 方法?因为那会很乏味...
        • 我认为明确声明它们本质上是使用 Typescript 的重点。另一种方法是使用&lt;any&gt;,它基本上恢复了(javascript)的动态特性。
        • 可以实现某种离线脚本,它是Promise.promisifyAll 的静态对应物。它将引用原始类型并生成带有*Async 函数的“附加修复”。
        • 真心希望typescript团队可以在漂亮的语言中添加一些promisifyAll
        猜你喜欢
        • 2022-01-23
        • 2022-11-03
        • 2021-05-22
        • 2016-07-19
        • 1970-01-01
        • 2016-04-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多