简体   繁体   中英

Conditional return type based on interface in typescript

I have a cache defined like this (snippet):

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

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

I would like to be able to define a function that when given a cache key like 'chapterDates' or 'kudosChecked' as a string, would return the value of the cache, with the proper type of that property.

So far I've tried the following using conditional types:

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> {
  [...]
}

I've also tried this:

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

None the solutions seem to make typescript understand that when the return type of eg getCache('kudosChecked') should be number[] . Currently it seems to think it's number[] | { [workId: string]: string[] } number[] | { [workId: string]: string[] } .

Am I going about this completely wrong or something, I'm pretty new-ish to typescript?

Okay so I finally figured out how to do it by going over a lot of typescript issues. The issue that helped was microsoft/Typescript#39305 . It proposes ValueOf as

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;

Using this new type we can then define getCache as so:

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

Typescript playground link

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM