Тип условного возврата TypeScript для функции generi c - PullRequest
2 голосов
/ 13 апреля 2020

Я хочу создать функцию, которая облегчит вывод структуры run в определении задачи ниже. Можно ли создать условное возвращаемое значение, чтобы inferTest1 имел тип { skipped: boolean; result: number }, а inferTest2 получало тип { skipped: boolean } без свойства результата?

interface TaskDefinition<T> {
  run: () => { skipped: boolean } | { skipped: boolean; result: T };
}

function createTask<T>(
  task: TaskDefinition<T>
): { skipped: boolean; result: T } | { skipped: boolean } {
  const taskResult = task.run();
  if ("result" in taskResult) {
    return {
      skipped: taskResult.skipped,
      result: taskResult.result,
    };
  }
  return {
    skipped: taskResult.skipped,
  };
}

const inferTest1 = createTask({
  run: () => ({
    skipped: false,
    result: 251,
  }),
});

const inferTest2 = createTask({
  run: () => ({
    skipped: false,
  }),
});

1 Ответ

2 голосов
/ 13 апреля 2020

Я думаю, что самым простым решением здесь было бы использовать перегрузки:

interface TaskDefinition<T> {
  run: () => { skipped: boolean } | { skipped: boolean; result: T };
}

function createTask<T>(task: { run: () => { skipped: boolean; result: T } }): { skipped: boolean; result: T }
function createTask(task: { run: () => { skipped: boolean } }): { skipped: boolean }
function createTask<T>(task: TaskDefinition<T>): { skipped: boolean; result: T } | { skipped: boolean } {
  const taskResult = task.run();
  if ("result" in taskResult) {
    return {
      skipped: taskResult.skipped,
      result: taskResult.result,
    };
  }
  return {
    skipped: taskResult.skipped,
  };
}

const inferTest1 = createTask({
  run: () => ({
    skipped: false,
    result: 251,
  }),
});
inferTest1.result

const inferTest2 = createTask({
  run: () => ({
    skipped: false,
  }),
});
inferTest2.result // err

Playground Link

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

Другим решением было бы вывести результат самого запуска, хотя это может помешать другим действиям, выполняемым в функции:


function createTask<T extends { skipped: boolean } | { skipped: boolean; result: T }>(task: { run: () => T }): T {
    const taskResult = task.run();
    // Only spreading or type assertions will work to satisfy T, also narrowing is now borken
    return {
        ...taskResult
    };
}

Playground Link

...