davidjenkins
davidjenkins

Reputation: 919

How should I extend the WebSocket type in TypeScript?

Rather than focus on the why, let's focus on the what.

I wanted to swap out the native WebSocket class with a user-defined class called WebSocketProxy. This way any time the code on the page attempted to create a new WebSocket it would actually be returned a new WebSocketProxy (I have my reasons).

To test this in it's most minimal form I wrote:

class WebSocketProxy extends WebSocket {

    constructor(url: string, protocols?: string | string[]) {
        super(url, protocols);
        /* Add hooks here. */
    }
}

WebSocket = WebSocketProxy; // Swap native WebSocket with WebSocketProxy.

The TypeScript compiler (Visual Studio 2015) translated this into:

var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var WebSocketProxy = (function (_super) {
    __extends(WebSocketProxy, _super);
    function WebSocketProxy(url, protocols) {
        _super.call(this, url, protocols); // This is what causes the error.
        /* Add hooks here. */
    }
    return WebSocketProxy;
})(WebSocket);
WebSocket = WebSocketProxy; // Swap native WebSocket with WebSocketProxy.

Thinking this would surely work, I was disappointed when I copied this into my Scratchpad in Firefox and executed.

TypeError: Constructor WebSocket requires 'new'

I got a similar (but more useful) error when doing the same in Chrome:

Uncaught TypeError: Failed to construct 'WebSocket': Please use the 'new' operator, this DOM object constructor cannot be called as a function.

I didn't get this error in Edge or Internet Explorer.

This behaviour leaves me wondering:

  1. How else should I produce my pseudo-WebSocket? (Perhaps implement instead of extend?)
  2. Is this strictly a Chrome/Firefox issue? Or is Microsoft's method of extending types falling short?
  3. Is attempting to extend a native type simply bad practice, or is this a special case?
  4. Why is calling WebSocket as a function forbidden in Chrome and Firefox?

Upvotes: 2

Views: 1864

Answers (1)

basarat
basarat

Reputation: 275819

How else should I produce my pseudo-WebSocket? (Perhaps implement instead of extend?)

You can do the following quite easily:

const OrigWebSocket = WebSocket;
WebSocket = function(url: string, protocols?: string | string[]){
    const self = new OrigWebSocket(url,protocols);
    /* Add hooks here. */
    return self;
} as any;

Is this strictly a Chrome/Firefox issue

Chrome/Firefox

Is attempting to extend a native type simply bad practice, or is this a special case

Special case

Why is calling WebSocket as a function forbidden in Chrome and Firefox?

To prevent user error ( WebSocket when they meant new WebSocket( )

More

This is very similar to https://github.com/sinonjs/sinon/issues/743 basically it is very stingy about being called with new so not easy to spy on.

Upvotes: 2

Related Questions