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
);
};