你能在 TypeScript 中指定条件返回值类型吗?

utp*_*mas 5 typescript

我编写了以下函数来帮助处理错误

const capture = <T>(
  callback: () => T
): { result?: T; error?: Error } => {
  try {
    return { result: callback(), error: undefined };
  } catch (err) {
    return { result: undefined, error: err as Error };
  }
};
Run Code Online (Sandbox Code Playgroud)

用法示例:

const { result, error } = capture<number>(() => foo());
if (error) badPath();

console.log("hooray we got a result", result)
Run Code Online (Sandbox Code Playgroud)

然而 TypeScript 编译器会抱怨:

Object is possibly 'undefined'. ts(2532)
const result: number | undefined
Run Code Online (Sandbox Code Playgroud)

我理解为什么编译器会抱怨(这是使用可选参数的预期行为)。

然而我想知道是否存在一些可以支持条件返回类型的 TypeScript 恶作剧。

即我们有没有办法指定capture的签名,以便当error不存在时,result推断存在?反之亦然?

GOT*_*O 0 5

  • 将函数的返回值定义capture{ result: T; error: undefined; } | { result: undefined; error: Error; }
  • 不要破坏返回类型;检查它的属性。在这种情况下,TypeScript 还不够智能,无法链接不同变量的类型。
const capture = function<T>(
  callback: () => T
): { result: T; error: undefined; } | { result: undefined; error: Error; } {
  try {
    return { result: callback(), error: undefined };
  } catch (err) {
    return { result: undefined, error: err as Error };
  }
}

const retVal = capture<number>(() => foo());
if (retVal.error)
    badPath();
else
    console.log("hooray we got a result", retVal.result);

Run Code Online (Sandbox Code Playgroud)

请参阅此游乐场链接

为了更健壮的实现,我们需要考虑抛出的错误不是 的实例的情况Errorerror在这种情况下,检查结果中属性的真实性是不够的。例如,我们可以在这里切换到测试属性error本身是否存在。为此,我们将返回类型更改为{ result: T; } | { error: unknown; }. 一个实现将如下所示:

const capture = function<T>(
  callback: () => T
): { result: T; } | { error: unknown; } {
  try {
    return { result: callback() };
  } catch (err) {
    return { error: err };
  }
}

const retVal = capture<number>(() => foo());
if ('error' in retVal)
    badPath();
else
    console.log("hooray we got a result", retVal.result);
Run Code Online (Sandbox Code Playgroud)

操场链接


Bru*_*oLM 1

这是不可能的,因为 TypeScript 不知道运行时。

我想到的最接近的事情是允许T未定义

(callback: () => T | undefined)
Run Code Online (Sandbox Code Playgroud)

然后将其与 一起过滤error,使代码的其余部分明白result此时是 anumber并且不能是未定义的。

此处的结果类型为数字

const capture = <T>(callback: () => T | undefined): { result?: T; error?: Error } => {
  try {
    return { result: callback(), error: undefined }
  } catch (err) {
    return { result: undefined, error: err as Error }
  }
}

const start = () => {
  const { result, error } = capture<number>(() => foo())
  if (error || !result) {
    // something
    return
  }

  // result // here it will be `number`
  // (cannot be undefined because we checked)

  console.log('hooray we got a result', result)
}
Run Code Online (Sandbox Code Playgroud)