[英]How to properly deal with promisifyAll in typescript?
Consider the following code:考虑以下代码:
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
will error out because it's created on the fly and not defined in any .d.ts
file. getAsync
会出错,因为它是动态创建的,并且没有在任何.d.ts
文件中定义。 So what is the proper way to handle this?那么处理这个问题的正确方法是什么?
Also, even though I have the .d.ts
files loaded for redis, I still need to cast redis
to any
to be used for promisifyAll
.此外,即使我为 redis 加载了
.d.ts
文件,我仍然需要将redis
为any
以用于promisifyAll
。 Otherwise, it will spill out error:否则,它会溢出错误:
Property 'RedisClient' does not exist on type 'typeof "redis"'
Is typing it to any
the only easy way to go?难道输入到
any
唯一的简单的方法去吗?
I'm solving this by declaration merging the setAsync
& getAsync
methods.我通过声明合并
setAsync
和getAsync
方法来解决这个问题。 I added the following code in my own custom .d.ts
file.我在自己的自定义
.d.ts
文件中添加了以下代码。
declare module "redis" {
export interface RedisClient extends NodeJS.EventEmitter {
setAsync(key:string, value:string): Promise<void>;
getAsync(key:string): Promise<string>;
}
}
Another way to do it which requires less code is to extend the Redis object like so:另一种需要较少代码的方法是像这样扩展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);
}
Notice that not all method signatures overwrite correctly, so you have to help typescript a little.请注意,并非所有方法签名都正确覆盖,因此您必须稍微帮助打字稿。
Now you can just use this enhanced class by creating it with your options, for example:现在您可以通过使用您的选项创建它来使用这个增强类,例如:
new AsyncRedis({
host: process.env.REDIS_HOST || '127.0.0.1',
password: process.env.REDIS_PASSWORD || 'whatever',
});
Just adding to Dave's answer, in my needs, I has to add in Multi for atomic operations.只是添加到 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
}
}
This solution works fine for me:这个解决方案对我来说很好:
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...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.