1

I have an onCall Firebase Cloud Function named getZohoDeskTicketById that throws an error like this:

throw new functions.https.HttpsError(
      'unknown',
      error.response.data.errorCode,
      error.response.data
);

And I am calling it like this:

import { httpsCallable, FunctionsError } from 'firebase/functions';    
// ...
const getZohoDeskTicketById = httpsCallable(functions, 'getZohoDeskTicketById');
const handleClick = async () => {
  try {
    const result = await getZohoDeskTicketById({
      ticketId: '345112301899997',
    });
    console.log(result);
  } catch (error) {
    if (error instanceof FunctionsError) { // TypeScript warning here
      console.log(error.code); // TypeScript warning here
      console.log(error.message); // TypeScript warning here
      console.log(error.details); // TypeScript warning here
    }
  }
};

But I'm having trouble with narrowing down the catch.

FunctionsError has a TypeScript warning of 'FunctionsError' only refers to a type, but is being used as a value here. ts(2693)

and

error on each of my console.log's has a TypeScript warning of Object is of type 'unknown'.ts(2571)

So what is the correct way of narrowing down this error?

TinyTiger
  • 1,801
  • 7
  • 47
  • 92
  • Does this answer your question? [Why does 'instanceof' in TypeScript give me the error "'Foo' only refers to a type, but is being used as a value here."?](https://stackoverflow.com/questions/46703364/why-does-instanceof-in-typescript-give-me-the-error-foo-only-refers-to-a-ty) – Dharmaraj Mar 27 '22 at 12:33
  • @Dharmaraj some of the links in that answer do explain the broader concept but I was looking for a more specific answer relating to Firebase Cloud Functions. It did help though, so thanks for linking, and I have added such an answer below. – TinyTiger Mar 27 '22 at 22:25

1 Answers1

1

I created a user-defined type guard like so:

function isFunctionsError(error: unknown): error is FunctionsError {
  return (error as FunctionsError).details !== undefined;
}

const handleClick = async () => {
  try {
    const result = await getZohoDeskTicketById({
      ticketId: '345112301899997',
    });
    console.log(result);
  } catch (error) {
    if (isFunctionsError(error)) {
      console.log(error.code);
      console.log(error.message);
      console.log(error.details);
    }
  }
};

But if anyone knows of a better way, please post it!

TinyTiger
  • 1,801
  • 7
  • 47
  • 92
  • Yup, using type predicates seems to be the correct way of arrow to an interface: https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates – abegehr Apr 06 '23 at 13:53