如何正确处理打字稿中的 promisifyAll?
How to properly deal with promisifyAll in typescript?
考虑以下代码:
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
。否则会溢出error:
Property 'RedisClient' does not exist on type 'typeof "redis"'
输入 any
是唯一简单的方法吗?
我正在通过 declaration merging setAsync
和 getAsync
方法解决这个问题。我在自己的自定义 .d.ts
文件中添加了以下代码。
declare module "redis" {
export interface RedisClient extends NodeJS.EventEmitter {
setAsync(key:string, value:string): Promise<void>;
getAsync(key:string): Promise<string>;
}
}
只是添加到 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
}
}
另一种需要较少代码的方法是像这样扩展 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);
}
请注意,并非所有方法签名都能正确覆盖,因此您必须稍微帮助打字稿。
现在您可以使用这个增强的 class 通过使用您的选项创建它,例如:
new AsyncRedis({
host: process.env.REDIS_HOST || '127.0.0.1',
password: process.env.REDIS_PASSWORD || 'whatever',
});
这个解决方案对我来说很好用:
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...
考虑以下代码:
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
。否则会溢出error:
Property 'RedisClient' does not exist on type 'typeof "redis"'
输入 any
是唯一简单的方法吗?
我正在通过 declaration merging setAsync
和 getAsync
方法解决这个问题。我在自己的自定义 .d.ts
文件中添加了以下代码。
declare module "redis" {
export interface RedisClient extends NodeJS.EventEmitter {
setAsync(key:string, value:string): Promise<void>;
getAsync(key:string): Promise<string>;
}
}
只是添加到 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
}
}
另一种需要较少代码的方法是像这样扩展 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);
}
请注意,并非所有方法签名都能正确覆盖,因此您必须稍微帮助打字稿。
现在您可以使用这个增强的 class 通过使用您的选项创建它,例如:
new AsyncRedis({
host: process.env.REDIS_HOST || '127.0.0.1',
password: process.env.REDIS_PASSWORD || 'whatever',
});
这个解决方案对我来说很好用:
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...