泛型函数的TypeScript条件返回类型

时间:2020-04-13 07:31:13

标签: typescript typescript-generics

我想创建一个函数,可以很容易地在下面的任务定义中推断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 个答案:

答案 0 :(得分:2)

我认为这里最简单的解决方案是使用重载:

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