Home > Blockchain >  Can you specify conditional return value types in TypeScript?
Can you specify conditional return value types in TypeScript?

Time:12-06

I have written the following function to help with error handling

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

Example usage:

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

console.log("hooray we got a result", result)

However the TypeScript compiler will complain:

Object is possibly 'undefined'. ts(2532)
const result: number | undefined

I understand why the compiler is complaining (this is expected behaviour for using optional params).

However I was wondering if there existed some TypeScript shenanigans that could support conditional return types.

i.e. is there a way we could specify capture's signature such that when error doesn't exist, result is inferred to exist? And vice versa?

CodePudding user response:

  • Define the return value of your capture function as { result: T; error: undefined; } | { result: undefined; error: Error; }.
  • Do not destructure the return type; check its properties instead. TypeScript is not smart enough yet to link the types of distinct variables in this case.
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);

See this result type here in number

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)
}
  • Related