如何根据传入的参数精确 `Promise` 返回的类型?

作者站长头像
站长
· 阅读数 19

演示: https://tsplay.dev/NB6axN

代码:

const action = {
  '/posts': () => Promise.resolve(['a']),
  '/test': () => Promise.resolve([1]),
} as const;

type test = ReturnType<ActionType['/test']>;

async function getData<T extends ItemKey>(url: T) {
  return await action[url]();
}

type ActionType = typeof action;
type ItemKey = keyof typeof action;

const post = getData('/posts');   // Promise<string[]>
const test = getData('/test');   // Promise<number[]>

结果:

  • 传入 '/posts' 拿到 Promise<string[]>
  • 传入 '/test' 拿到 Promise<number[]>

前置条件:

  • 尽可能不要强行断言
回复
1个回答
avatar
test
2024-06-21

尝试了一下

const action = {
  '/posts': () => Promise.resolve(['a']),
  '/test': () => Promise.resolve([1]),
} as const;

type test = ReturnType<ActionType['/test']>;

type ActionType = typeof action;
type ItemKey = keyof typeof action;
type DePromise<T> = T extends Promise<infer R> ? R : T;
type InferResult<T extends ItemKey> = DePromise<ReturnType<ActionType[T]>>;

async function getData<T extends ItemKey>(url: T): Promise<InferResult<T>> {
   return await action[url]() as InferResult<T>;
}


const post = getData('/posts');   // Promise<string[]>
const test = getData('/test');   // Promise<number[]>

传送门:http://u5a.cn/qcTA9

尝试的时候遇到些问题:

  1. async 函数的返回类型必须是 Promise<?>,没办法,只好先 DePromise 之后再把 Promise 加上。
  2. await action[url]() 自动推导出来的类型是 number[] | string[],所以只好用 as InferResult<T> 强制声明类型。
回复
likes
适合作为回答的
  • 经过验证的有效解决办法
  • 自己的经验指引,对解决问题有帮助
  • 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
  • 询问内容细节或回复楼层
  • 与题目无关的内容
  • “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容