基于打字稿中的接口的条件返回类型

时间:2020-06-27 20:56:54

标签: typescript

我有一个定义如下的缓存(片段):

interface Cache {
  chapterDates: { [workId: string]: string[] };
  kudosChecked: number[];
}

export const DEFAULT_CACHE: Cache = {
  chapterDates: {},
  kudosChecked: [],
};

我希望能够定义一个函数,当给它一个诸如“ chapterDates”或“ kudosChecked”之类的缓存键作为字符串时,它将以适当的属性类型返回缓存的值。

到目前为止,我已经尝试使用条件类型进行以下操作:

type Test<T> = T extends 'chapterDates'
  ? { [workId: string]: string[] }
  : T extends 'kudosChecked'
  ? number[]
  : never;

export async function getCache<T extends keyof Cache, R extends Test<T>>(
  id: T
): Promise<R> {
  [...]
}

我也尝试过:

export async function getCache<
  T extends keyof Cache,
  R extends Cache[T]
>(id: T): Promise<R> {
  [...]
}

解决方案似乎都无法使打字稿理解例如返回类型为getCache('kudosChecked')应该是number[]。目前似乎认为它是number[] | { [workId: string]: string[] }

我要完全解决这个问题吗?我对打字稿很陌生吗?

1 个答案:

答案 0 :(得分:0)

好的,所以我终于解决了许多打字稿问题,终于找到了解决方法。帮助的问题是microsoft/Typescript#39305。它建议ValueOf

type KeyOf<
  U,
  C = unknown,
  K extends U extends unknown ? keyof U : never = U extends unknown
    ? keyof U
    : never
> = C extends unknown
  ? U extends unknown
    ? K extends unknown
      ? U[K] extends C
        ? K
        : never
      : never
    : never
  : never;

type ValueOf<U, K extends KeyOf<U> = KeyOf<U>> = U extends unknown
  ? K extends keyof U
    ? U[K]
    : never
  : never;

使用这种新类型,我们可以这样定义getCache

export async function getCache<K extends CacheId, R = ValueOf<Cache, K>>(
  id: K
): Promise<R> {
  [...]
}

Typescript playground link