Typescript:如何将Map与动态值类型一起使用?

bweufnob  于 2023-04-13  发布在  TypeScript
关注(0)|答案(2)|浏览(133)

我正在尝试在Typescript中实现一个“缓存服务”。该高速缓存的主“桶”应该是Map。到目前为止,我想到了这个:

interface CacheItem {
  value: Observable<any>;
  // validUntil: Date; // removed for simplification
}

private readonly cacheMap = new Map<string, CacheItem>();

public cachify<T>(cacheKey: string, cacheableFunction: () => Observable<T>): Observable<T> {
    const itemExists = this.cacheMap.has(cacheKey);

    if (!itemExists) {
      this.cacheMap.set(cacheKey, {
        value: cacheableFunction().pipe(shareReplay())
      });
    }

    return this.cacheMap.get(cacheKey).value;
}

然后可以这样使用:

return this.cacheService
    .cachify('great-cache-key', () => fetchSomethingNice);

到目前为止,这工作正常。现在我想删除any的使用。所以我将服务部分更改为:

interface CacheItem<T> { // T here
  value: Observable<T>; // and T here
}

private readonly cacheMap = new Map<string, CacheItem<unknown>>(); // unknown here because we now have to provide a type for CacheItem

初始化也必须改变,因为我们永远不知道服务的类型inside。这样,cachify将在最后一行(return this.cacheMap...)给予我一个错误:

Type 'Observable<unknown>' is not assignable to type 'Observable<T>'.
  Type 'unknown' is not assignable to type 'T'.
    'T' could be instantiated with an arbitrary type which could be unrelated to 'unknown'.

我有点明白T和未知在一起是有问题的,但不知道如何解决它。

编辑我创建了一个stackblitz来显示问题:https://stackblitz.com/edit/rxjs-siunfk?devToolsHeight=33&file=index.html

ecfsfe2w

ecfsfe2w1#

这里需要一个as或其他退出窗口,因为cacheMap的类型不知道每个缓存项的类型。
你也许可以写一个强类型的缓存,像这样:

type CacheMap = {
    greatCacheKey?: CacheItem<SomethingNice>
    gorgeousCacheKey?: CacheItem<DeliciousTreat>
    ...
}

function cachify<Key extends keyof CacheMap>(key: Key, cacheableFunction: () => Observable<CacheMap[Key]>) { ... }
5f0d552i

5f0d552i2#

将类型参数提升到类级别(如@Jerryh001所建议的那样),就不需要使用unknown并使代码能够编译。
这是编译的版本。

class CacheService<T> {
  private readonly cacheMap = new Map<string, CacheItem<T>>();
  public cachify(
    cacheKey: string,
    cacheableFunction: () => Observable<T>
  ): Observable<T> {
    const itemExists = this.cacheMap.has(cacheKey);

    if (!itemExists) {
      this.cacheMap.set(cacheKey, {
        value: cacheableFunction().pipe(shareReplay()),
      });
    }

    return this.cacheMap.get(cacheKey).value;
  }
}

相关问题