Сопоставить условные типы с типом объединения? - PullRequest
0 голосов
/ 02 ноября 2018

Я пытаюсь сделать следующее (также увидеть его на площадке TypeScript ), но я получаю сообщение об ошибке в возвращаемом типе функции, которое говорит мне, что условный тип не может быть назначен объединению :

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 (как обещание).

Как я могу заставить эту работу работать, чтобы тип аргумента type определял тип возвращаемого Promise?


Вот другой способ сделать это без условных типов, но я хочу знать, можно ли это сделать, используя условный тип для type аргумента.


РЕДАКТИРОВАТЬ: Основываясь на ответе Эрика ниже, мне также любопытно, почему этот не будет работать, и если возможно заставить его работать без переопределения ResponseResult и без изменения типа возврата функция.

@ Эрик, второй пример .

Ответы [ 2 ]

0 голосов
/ 02 ноября 2018

В качестве альтернативы, чтобы заставить работать вывод типов, вы можете предоставить объявления переопределения:

type ResponseResult = string | number | boolean

async function sendWorkRequest(type: 'foo', ...params): Promise<string>
async function sendWorkRequest(type: 'bar', ...params): Promise<number>
async function sendWorkRequest(type: 'baz', ...params): Promise<boolean>
async function sendWorkRequest(type: RequestType, ...params): Promise<ResponseResult> {
  /* ... */
  const p = new Promise<ResponseResult>((/* ... */) => {/* ... */})
  /* ... */
}

// WORKS
async function test1() {
  const result = await sendWorkRequest('foo')
  result.split('')
}

test1()
0 голосов
/ 02 ноября 2018

Вы должны инкапсулировать тип как ( допущение ). Тип сценария не может предполагать (вычислять), что два не ссылающихся условных типа совпадают.

Так что вместо этого

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

Знаете ли вы, почему или как это сделать без изменения типа возвращаемого значения и без изменения определения типа возвращаемого значения?

Нет, потому что Conditional Type не равно Type.

Требуется ли для этого явное приведение типов в месте вызова функции?

Нет, я могу смоделировать обещание со свойством типа и увидеть, что оно того типа:

Пример TypeScript Playground

Есть ли способ сделать его безопасным (без приведения типа)?

Не обязательно

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...