Monday 25 April 2022

React Native TypeScript WebSocket onerror Value of "this" must be of type Event

I'm trying to implement WebSocket support into my app by following React Native's own tutorial at https://reactnative.dev/docs/network#websocket-support.

Here is my code:

function initializeSocket(socket:WebSocket){
    socket.onopen = () => {
        store.dispatch(toggleWebsocketConnected(true));
    };
    socket.onclose = () => {
        store.dispatch(toggleWebsocketConnected(false));
    };
    socket.onerror = (e:any) => {
        console.log('websocket error', e);
        store.dispatch(toggleWebsocketConnected(false));
    };
    socket.onmessage = (e) => {
        processMessage(e);
    };
}

In onerror event handler (for now, ignore why error handler is called, this is not a "why can't I connect" question, but a TypeScript question) when it's triggered I'm getting a weird error at runtime:

TypeError [ERR_INVALID_THIS]: Value of "this" must be of type Event
    at new NodeError (/path/to/my/project/lib/internal/errors.js:371:5)
    at Event.[nodejs.util.inspect.custom] (/path/to/my/project/lib/internal/event_target.js:120:13)
    at formatValue (/path/to/my/project/lib/internal/util/inspect.js:763:19)
    at inspect (/path/to/my/project/lib/internal/util/inspect.js:340:10)
    at formatWithOptionsInternal (/path/to/my/project/lib/internal/util/inspect.js:2006:40)
    at formatWithOptions (/path/to/my/project/lib/internal/util/inspect.js:1888:10)
    at console.value (/path/to/my/project/lib/internal/console/constructor.js:323:14)
    at console.log (/path/to/my/project/lib/internal/console/constructor.js:359:61)
    at EventTarget.socket.onerror (/path/to/my/project/src/services/myproject/socket.ts:27:17)
    at EventTarget.dispatchEvent (/path/to/my/project/.vscode/.react/index.bundle:31193:27) {code: 'ERR_INVALID_THIS', stack: 'TypeError [ERR_INVALID_THIS]: Value of "this"…/myproject/.vscode/.react/index.bundle:31193:27)', message: 'Value of "this" must be of type Event', toString: ƒ, Symbol(kIsNodeError): true}

Vscode linter shows everything is fine though. When I hover over the onerror function it shows:

(property) WebSocket.onerror: ((this: WebSocket, ev: Event) => any) | null

Two input arguments. So eventhough Vscode isn't complaining about my initial code, I also tried to change it to the following:

 socket.onerror = (_:any, e:any) => {
    console.log('websocket error', e);
    store.dispatch(toggleWebsocketConnected(false));
 };

Now, Vscode linter shows an error:

Type '(_: any, e: any) => void' is not assignable to type '(this: WebSocket, ev: Event) => any'.ts(2322)

If I run the code regardless of the error, I don't get a runtime error, yet _ is now an actual event object and e is undefined:

enter image description here

What am I doing wrong? What is the correct form of doing it? I've stumbled upon a weird problem with this keyword in arguments and TypeScript before (see Why are rest parameters undefined in TypeScript?) which indeed turned to be a Babel bug, which is now merged and fixed long ago.

How can I get it to work correectly?

UPDATE: I've managed to "work around" by turning the arrow function into a function with a function keyword:

    socket.onerror = function(this:any, e:Event){
        console.log('websocket error', e);
        store.dispatch(toggleWebsocketConnected(false));
    };

It "works" now, though this is not an actual solution as I still can't use arrow functions, breaking my code style as I never use function keyword functions in code (other than top-level simple definitions) anywhere in the app.

No it doesn't, it seemed to step correctly yet actually threw an error again when I reached a line to console.log the event.



from React Native TypeScript WebSocket onerror Value of "this" must be of type Event

No comments:

Post a Comment