Implementing custom error handling using Comlink in TypeScript

While working on the UI process, I need to capture custom Errors thrown in a Webworker using comlink.

The custom Error is an extended Error type, so comlink serializes/deserializes it as a regular Error object, not as a custom Error.

Serialization:

if (value instanceof Error) {
  serialized = {
    isError: true,
    value: {
      message: value.message,
      name: value.name,
      stack: value.stack,
    },
  };
}

Link to Source Code - Line 248

Deserialization:

if (serialized.isError) {
  throw Object.assign(
    new Error(serialized.value.message),
    serialized.value
  );
}

Link to Source Code - Line 265

I attempted to customize the throwTransferHandler to throw custom Errors, but was unsuccessful. This is because throwMarker is a unique Symbol and not exported.

canHandle: (value): value is ThrownValue =>
  isObject(value) && throwMarker in value,

Link to Source Code - Line 245

Answer №1

I took the approach of defining a local module that reexports comlink and utilizes serialize-error for custom error serialization/deserialization

import * as Comlink from "comlink";
import ErrorCodec from "serialize-error";
export * from "comlink";

interface ThrownValue {
  value: unknown;
}
type SerializedThrownValue =
  | { isError: true; value: ErrorCodec.ErrorObject }
  | { isError: false; value: unknown };

const throwTransferHandler_:
  | Comlink.TransferHandler<unknown, unknown>
  | undefined = Comlink.transferHandlers.get("throw");

const throwTransferHandler = throwTransferHandler_ as Comlink.TransferHandler<
  ThrownValue,
  SerializedThrownValue
>;

const throwTransferHandlerCustom: Comlink.TransferHandler<
  ThrownValue,
  SerializedThrownValue
> = {
  canHandle: throwTransferHandler.canHandle,
  serialize: ({ value }) => {
    let serialized: SerializedThrownValue;
    if (value instanceof Error) {
      serialized = {
        isError: true,
        value: ErrorCodec.serializeError(value),
      };
    } else {
      serialized = { isError: false, value };
    }
    return [serialized, []];
  },
  deserialize: (serialized) => {
    if (serialized.isError) {
      const error = ErrorCodec.deserializeError(serialized.value);
      throw error;
    }
    throw serialized.value;
  },
};

Comlink.transferHandlers.set("throw", throwTransferHandlerCustom);

It is important to ensure that this version of the module is imported in all other locations instead of directly importing comlink


As an alternative, you can also use getOwnPropertySymbols and toString within canHandle:

Object.getOwnPropertySymbols({[Symbol("Comlink.thrown")]: 1})
  .some(_ => _.toString() === 'Symbol(Comlink.thrown)')

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Utilizing UI-GRID to showcase JSON information

I am currently in the process of fetching data from the server. [ { id:1, name:demo, request: { id: 1, localCompany: { id: 1 } } }] [{ }, { }] This is how my JSON object appears to be structured. After calling ...

Shuffle and Place indented list

I have a bunch of ideas and a list of projects. I need to choose one idea and match it with a project. I followed this guide to implement the drag and drop feature, but encountered an issue where every project gets assigned the same idea when dragging and ...

Encountering difficulty when integrating external JavaScript libraries into Angular 5

Currently, I am integrating the community js library version of jsplumb with my Angular 5 application (Angular CLI: 1.6.1). Upon my initial build without any modifications to tsconfig.json, I encountered the following error: ERROR in src/app/jsplumb/jspl ...

Troubleshoot Typescript scripts within a Docker container using VSCode

I've been struggling with this problem for a few hours now and can't find a solution anywhere - My Node API is running in a Docker container, coded in Typescript, and I'm attempting to debug it using VSCode. I am able to establish a connect ...

Using a decorator with an abstract method

Discussing a specific class: export abstract class CanDeactivateComponent { abstract canLeavePage(): boolean; abstract onPageLeave(): void; @someDecorator abstract canDeactivateBeforeUnload(): boolean; } An error occurred stating that A decorat ...

What is the most effective method for iterating through millions of records in Angular or TypeScript?

Looking for a solution to load multiple multi-select drop-downs with cascading effect based on related data. I am dealing with millions of records retrieved from an API, some of which are duplicates in one column but unique when considering all columns. ...

Using React to make an API request depending on the selected option

In my code, I have a function that receives the value of a selected option. There are three different select options (level, facility, host), and when an option is selected, its value is sent to this function. private optionFilterHandler = (option: string ...

Encountering a tslint issue: "Parsing error: Expression expected"

Could someone provide some insight on this issue? I’m encountering an error message that says Failed to compile. Parsing error: Expression expected with this specific line of code - isLogViewVisible: dashboard?.logView !== null where the variable isLog ...

Trying to use 'X' before it has been initialized is not allowed

I have encountered an issue while attempting to create a child class within my parent class. Here is the code snippet: class Stage { a() { return new ChestStage(); } } Below is the child class code: class ChestStage extends Stage { ...

Having issues with the toggle display button functionality not working properly in Angular when using click()

One of the files in my project is named server.component.ts and another is named server.component.html. This is how my server.component.ts file is structured: import { Component } from '@angular/core'; @Component({ selector: 'app-server& ...

Fuzziness occurrence in distinct vue element

My Situation I have a custom DropDown with a filter text input above. The DropDown can be opened independently from the filter text input. My Goal I want the DropDown to close when the filter input loses focus and also when I click outside of the Drop ...

angular2 - Having trouble retrieving data from subject

Why am I unable to successfully initialize and retrieve data from a service using a subject in Angular? HomeComponentComponent.TS export class HomeComponentComponent implements OnInit { public homeSub; constructor( private subService: SubjectServ ...

What is the method for passing arguments in TypeScript functions?

Having an issue with a TypeScript method that I've written: createSomeData(args: { data: Data, helpfulInfo?: Info, context?: UIContext }): Promise<IDataModel>; The main problem I'm facing is that I can't seem to call it properly. I at ...

Understanding how to deduce parameter types in TypeScript

How can I infer the parameter type? I am working on creating a state management library that is similar to Redux, but I am having trouble defining types for it. Here is the prototype: interface IModel<S, A> { state: S action: IActions<S, A&g ...

Display the pre-selected option in mat-select in an Angular application

Need help with displaying the selected option in mat-select using Angular 11. The scenario is as follows: I have a field named Idefault, and the condition is, if type.Idefault == true, then show the value as the selected option in mat-select. An image has ...

Successfully generated files, now patiently awaiting typecheck results... encountering an issue with importing SASS modules

Issue Encountering a problem where adding SASS variables to TypeScript files causes the browser tab with an open devserver to hang, displaying Files successfully emitted, waiting for typecheck results.... Trying to figure out what's causing this iss ...

What are the steps to add code into the Monaco Editor using Playwright?

As I explore the world of Playwright, I am faced with a challenge regarding testing a feature that involves a monaco editor. Unfortunately, my search in Playwright documentation and forums did not yield any relevant information. Here is the test scenario ...

Angular 13 does not currently have support for the experimental syntax 'importMeta' activated

Since upgrading to angular 13, I've encountered an issue while attempting to create a worker in the following manner: new Worker(new URL('../path/to/worker', import.meta.url), {type: 'module'}) This code works as expected with "ng ...

The value returned by elementRef.current?.clientHeight is not the correct height of the element

I've encountered a peculiar issue with my code where the reported height of an element does not match its actual size. The element is supposed to be 1465px tall, but it's showing up as 870px. I suspect that this discrepancy might be due to paddin ...

Offering a limited selection of generic type options in TypeScript

Is there a shorthand in TypeScript for specifying only some optional types for generic types? For example, let's say I have a class with optional types: class GenericClass<A extends Type1 = Type1, B extends Type2 = Type2, C extends Type3 = Type3> ...