Home > Mobile >  Pass class definition as parameter & reference static member in TypeScript
Pass class definition as parameter & reference static member in TypeScript

Time:03-16

I am trying to pass a class definition as a parameter to a function and then access a static member of the class inside the function, but Typescript says the static property doesn't exist on the type and asks if I want to access the static member instead. I do, but can't figure out how to specify the type of the parameter in such a way that this is allowed. It feels like this should be simple and I'm just missing some small detail, but what is it?

Code example, referencing this library:

import Web3 from 'web3';

//With a first param typed Web3 regardless of name, Typescript throws an error:
//Property 'providers' does not exist on type 'Web3'.
//Did you mean to access the static member 'Web3.providers' instead?ts(2576)
const getWebSocketProvider = function(
        Web3ClassDefinition: Web3, 
        host: string, 
        port: string
    ) {
    //Custom options and other components motivating use of a wrapper function
    //are removed for this minimal example.
    //Adding .constructor just before .providers changes the error to
    //"Property 'providers' does not exist on type 'Function'.ts(2339)"
    //Adding .prototype.constructor just before .providers changes the error to
    //"Property 'prototype' does not exist on type 'Web3'.ts(2339)"
    return new Web3ClassDefinition.prototype.constructor.providers.WebsocketProvider(
        'wss://' host ':' port
    );
};

//This call also has an error:
//Argument of type 'typeof Web3' is not assignable to parameter of type 'Web3'.
//Type 'typeof Web3' is missing the following properties from type 'Web3':
//defaultAccount, defaultBlock, currentProvider, setProvider, and 5 more.ts(2345)
//https://stackoverflow.com/a/43607255/798371 solves that, 
//but then the main error changes to
//"Property 'providers' does not exist on type Constructor<Web3>."
getWebSocketProvider(Web3, '123.45.67.89', '1234');

Note that the type definition in the GPL-licensed library (index.d.ts) includes the static providers member:

export default class Web3 {
    constructor();
    constructor(provider: provider);
    constructor(provider: provider, net: net.Socket);
    //...
    static readonly providers: Providers;
    //...
}

CodePudding user response:

The issue is that the type Web3 denotes an instance of the Web3 class rather than the class itself. To pass the class itself as a parameter, you will need to use the type typeof Web3. This is also what the somewhat cryptic type error tries to convey: Argument of type 'typeof Web3' (i.e. actual parameter Web3) is not assignable to parameter of type 'Web3' (i.e. formal parameter Web3ClassDefinition).

If you change the type of Web3ClassDefinition to typeof Web3, and drop the .prototype.constructor part, the code type checks:

const getWebSocketProvider = function(
        Web3ClassDefinition: typeof Web3, 
        host: string, 
        port: string
    ) {
    return new Web3ClassDefinition.providers.WebsocketProvider(
        'wss://' host ':' port
    );
};

TypeScript playground

  • Related