我想创建一个函数,可以很容易地在下面的任务定义中推断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,
}),
});
答案 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
您也可以使用条件类型,但是我认为这太过分了。
另一种解决方案是推断运行本身的结果,尽管这可能会干扰您在函数中执行的其他操作:
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
};
}