Why am I getting a TypeScript type error in this Effector effect subscriber?

593 views Asked by At

I'm working on a front-end app using React, Typescript, Effector, FetchAPI and more. I made an Effector effect to delete an item in my backend:

export const deleteItemFX = createEffect({
  handler: (id: string) => {
    return fetch(itemUrl + id, {
      method: "DELETE",
    });
  }
})

Now in my React component, I import my effect and add a subscriber to its 'finally' event, as per the documentation:

deleteItemFX.finally.watch(({params, status, result}) => {
    console.log('finally.watch called');
    if (result.ok) {
      result.json().then(() => {
        message.success(t("delete_item.success"));
      })
    }
  });

My code does not compile because of the following type error:

Property 'result' does not exist on type '{ status: "done"; params: string; result: Response; } | { status: "fail"; params: string; error: Error; }'.  TS2339

Does anyone know what I can do to get the 'result' of my handler in my 'finally.watch' function?

1

There are 1 answers

2
josephjnk On BEST ANSWER

The problem is that you're trying to pull out the property result when you destructure the argument to watch, before you check whether status equals "done" or "fail".

Look at the error message: the property result does not exist on the type:

{ status: "done"; params: string; result: Response; }
| { status: "fail"; params: string; error: Error; }

This is a union of two object types; to read a property from a union, that property must exist on both sides of the union. result only exists on the first case, not on the second. So before you try to read it, you need to make sure that the data you have belongs to the first case. You do this by using an if statement to refine the type:

deleteItemFX.finally.watch(response => {
    console.log('finally.watch called');
    if (response.status === "fail") {
        // Handle error here. TypeScript knows that we're in the
        // second case of the union type here, so response.error
        // is available inside this block
        return;
    }

    // Now TypeScript knows that we're in the first case of the union,
    // and that response.result exists, so we can read it
    if (response.result.ok) {
      result.json().then(() => {
        message.success(t("delete_item.success"));
      })
    }
  });