首页 > 解决方案 > 将条件类型映射回联合类型?

问题描述

我正在尝试执行以下操作(也可以在 TypeScript Playground 上查看),但是函数的返回类型出现错误,告诉我条件类型不能分配给联合:

type RequestType =
  | 'foo'
  | 'bar'
  | 'baz'

interface SomeRequest {
  id: string
  type: RequestType
  sessionId: string
  bucket: string
  params: Array<any>
}

type ResponseResult = string | number | boolean

async function sendWorkRequest<T extends RequestType>(
    type: T,
    ...params
  ): Promise<
    T extends 'foo'
      ? string
      : T extends 'bar'
        ? number
        : T extends 'baz' ? boolean : never
  > {
    await this.readyDeferred.promise

    const request: SomeRequest = {
      id: 'abc',
      bucket: 'bucket',
      type,
      sessionId: 'some session id',
      params: [1,'two',3],
    }
    const p = new Promise<ResponseResult>((/*...*/) => {/*...*/})

    this.requests[request.id] = p
    this.worker.postMessage(request)
    return p // <-------------------------------- ERROR
  }

基本上,我希望条件类型产生其中一种ResponseResult类型。因此,根据type传递给函数的参数,它应该返回ResponseResult联合中的一种类型(作为 Promise)。

我怎样才能使它工作,以便type参数的类型确定返回的 Promise 的类型?


这是另一种没有条件类型的方法,但我想知道是否可以使用typearg 的条件类型来完成。


编辑:根据 Erik 在下面的回答,我也很好奇为什么这个不起作用,以及是否可以在不重新定义ResponseResult和不更改函数返回类型的情况下使其工作。

@Erik,第二个例子

标签: javascripttypescriptgenericsconditional-types

解决方案


您需要将 Type 封装为(假设)打字稿不能假设(计算)两个非引用条件类型是相同的。

所以改为

type ResponseResult<T> =
  T extends 'foo'
    ? string
    : T extends 'bar'
      ? number
      : T extends 'baz' ? boolean : never;

现在您可以将函数的签名更改为:

async function sendWorkRequest<T extends RequestType>(
  type: T,
  ...params
  ): Promise<ResponseResult<T>> {

并更新p

const p = new Promise<ResponseResult<T>>(() => { });

TypeScript Playground 示例

你知道为什么或如何在不改变返回类型和不修改返回类型定义的情况下这样做吗?

不,因为 aConditional Type不等于 a Type

那是否需要在调用函数的地方进行显式类型转换?

不,我可以使用 type 属性来模拟 Promise 并查看它是否属于该类型:

TypeScript Playground 示例

有没有办法让它安全(没有类型转换)?

不必要


推荐阅读