开发环境
- 
Nest.js v10.0.1 其他 npm 包版本如下 
| 12
 3
 4
 5
 
 | "@nestjs/cache-manager": "^2.0.1","cache-manager": "^5.2.3",
 "cache-manager-redis-store": "^3.0.1",
 "cache-manager-redis-yet": "^4.1.2",
 "redis": "^4.6.7",
 
 | 
背景
最近笔者在学习 node.js,选择了Nestjs作为后端框架,在掘金上找了篇文章(后文简称教程)跟着一起敲,那位作者使用的是Nestjs v8的版本,因此在redis相关的章节遇到了问题,最后参考了官方文档官方文档以及相关npm包的Github Issue中的内容,暂时解决了。笔者百度了很久Nestjs相关的redis教程,普遍都比较老了,也基本是大同小异,因此笔者打算写这篇文章作为记录。
问题复现
教程中的代码:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 
 | import { ConfigModule, ConfigService } from '@nestjs/config';import { RedisCacheService } from './redis-cache.service';
 import { CacheModule, Module, Global } from '@nestjs/common';
 import * as redisStore from 'cache-manager-redis-store';
 
 @Module({
 imports: [
 CacheModule.registerAsync({
 isGlobal: true,
 imports: [ConfigModule],
 inject: [ConfigService],
 useFactory: async (configService: ConfigService) => {
 return {
 store: redisStore,
 host: configService.get('REDIS_HOST'),
 port: configService.get('REDIS_PORT'),
 db: 0,
 auth_pass:  configService.get('REDIS_PASSPORT')
 };
 },
 }),
 ],
 providers: [RedisCacheService],
 exports: [RedisCacheService],
 })
 export class RedisCacheModule {}
 
 | 
发现useFactory函数部分报错,是一个TS错误:

解决问题?
问题出现的原因是此处useFactory函数需要返回一个类型为Promise<CacheModuleOptions<StoreConfig>> | CacheModuleOptions<StoreConfig>的值,很显然笔者此时返回的对象有问题。
| 12
 3
 4
 5
 6
 7
 8
 
 | export interface CacheModuleAsyncOptions<StoreConfig extends Record<any, any> = Record<string, any>> extends ConfigurableModuleAsyncOptions<CacheModuleOptions<StoreConfig>, keyof CacheOptionsFactory> {useExisting?: Type<CacheOptionsFactory<StoreConfig>>;
 useClass?: Type<CacheOptionsFactory<StoreConfig>>;
 useFactory?: (...args: any[]) => Promise<CacheModuleOptions<StoreConfig>> | CacheModuleOptions<StoreConfig>;
 inject?: any[];
 extraProviders?: Provider[];
 isGlobal?: boolean;
 }
 
 | 
从报错中可以看出,问题基本出在这个store上,而这个store的类型是由cache-manager-redis-store 这个npm包决定的,因此查看这个包有什么变动。
由于版本的升级,该包已经可以按需引入了,因此我们使用
| 1
 | import { redisStore } from 'cache-manager-redis-store';
 | 
同时,写法也有所变化:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | @Module({imports: [
 CacheModule.registerAsync({
 ...
 useFactory: async (configService: ConfigService) => {
 return {
 store: redisStore({
 socket: {
 host: configService.get('REDIS_HOST'),
 port: configService.get('REDIS_PORT'),
 },
 database: configService.get('REDIS_DB'),
 password: configService.get('REDIS_PASSWORD'),
 }),
 };
 },
 ...
 })
 
 | 
发现还是报错,但是错误信息不同:

核心是这句:Type 'Promise<RedisStore>' is not assignable to type 'string | CacheStoreFactory | CacheStore'.
也就是说类型还是不匹配。
查阅官方文档,发现文档相当之老,但是有一个Warning引起了笔者的注意:

当场点开了这个issue,让我康康。
解决问题!

这个npm包的作者提出了解决方案://@ts-ignore  😅
加入代码后,能正常的跑起来了,但是在写入值的时候,又报错了:
[Nest] 75156  - 06/28/2023, 3:10:41 PM   ERROR [ExceptionsHandler] store.set is not a function
于是继续看这个issue,发现了解决方案,似乎是和异步有关系
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | @Module({imports: [
 CacheModule.registerAsync({
 ...
 
 useFactory: async (configService: ConfigService) => {
 const store = await redisStore({
 ...
 });
 return {
 store,
 };
 },
 }),
 ...
 })
 
 | 
这样报错就解决了,redis也能正常使用了
但是笔者作为一个高贵的TS使用者,怎么能接受自己的代码中有@ts-ignore出现呢???这也太不专业了,正巧,issue中也有老哥跟笔者一个想法,因此「 优化版 」出现了。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | @Module({imports: [
 CacheModule.registerAsync({
 ...
 useFactory: async (configService: ConfigService) => {
 const store = await redisStore({
 ...
 });
 return {
 store: store as unknown as CacheStore,
 };
 },
 }),
 ...
 })
 
 | 
看起来舒服了一点,但是issue中有硬核老哥觉得这还不行,作者一直不改,那就自己改,于是魔改了这个包,发布了另一个包cache-manager-redis-yet,这个替换这个包就可以了,两者就最后一个单词不同。
| 12
 
 | cache-manager-redis-storecache-manager-redis-yet
 
 | 
至此问题基本解决了:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 
 | import { redisStore } from 'cache-manager-redis-yet';import type { RedisClientOptions } from 'redis';
 ...
 
 @Module({
 imports: [
 CacheModule.registerAsync<RedisClientOptions>({
 ...
 useFactory: async (configService: ConfigService) => {
 const store = await redisStore({
 ...
 });
 return {
 store: store,
 };
 },
 }),
 ...
 })
 
 | 
总结
解决方式有两种(前提是你已经使用了新的写法):
希望笔者的文章能帮到你。