-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Fix typing compatibility when linking a contract to a context #5416
Changes from 1 commit
9cae1f9
3e3cb8e
d43ac3a
6408b57
d93c86c
37cec51
903d642
b35c32f
4942447
648a5c7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -72,21 +72,21 @@ export type Web3ContextInitOptions< | |
|
|
||
| export type Web3ContextConstructor< | ||
| // eslint-disable-next-line no-use-before-define, @typescript-eslint/no-explicit-any | ||
| T extends Web3Context<any>, | ||
| T extends Web3Context, | ||
| T2 extends unknown[], | ||
| > = new (...args: [...extras: T2, context: Web3ContextObject]) => T; | ||
|
|
||
| // To avoid circular dependencies, we need to export type from here. | ||
| export type Web3ContextFactory< | ||
| // eslint-disable-next-line no-use-before-define, @typescript-eslint/no-explicit-any | ||
| T extends Web3Context<any>, | ||
| T extends Web3Context, | ||
| T2 extends unknown[], | ||
| > = Web3ContextConstructor<T, T2> & { | ||
| fromContextObject(this: Web3ContextConstructor<T, T2>, contextObject: Web3ContextObject): T; | ||
| }; | ||
|
|
||
| export class Web3Context< | ||
| API extends Web3APISpec, | ||
| API extends Web3APISpec = any, | ||
| RegisteredSubs extends { | ||
| [key: string]: Web3SubscriptionConstructor<API>; | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
|
|
@@ -95,7 +95,7 @@ export class Web3Context< | |
| public static readonly providers = Web3RequestManager.providers; | ||
| public static givenProvider?: SupportedProviders<never>; | ||
| public readonly providers = Web3RequestManager.providers; | ||
| protected _requestManager: Web3RequestManager<API>; | ||
| protected _requestManager: Web3RequestManager<API | any>; | ||
Muhammad-Altabba marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| protected _subscriptionManager?: Web3SubscriptionManager<API, RegisteredSubs>; | ||
| protected _accountProvider?: Web3AccountProvider<Web3BaseWalletAccount>; | ||
| protected _wallet?: Web3BaseWallet<Web3BaseWalletAccount>; | ||
|
|
@@ -174,14 +174,14 @@ export class Web3Context< | |
| } | ||
|
|
||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| public static fromContextObject<T extends Web3Context<any>, T3 extends unknown[]>( | ||
| public static fromContextObject<T extends Web3Context, T3 extends unknown[]>( | ||
| this: Web3ContextConstructor<T, T3>, | ||
| ...args: [Web3ContextObject, ...T3] | ||
| ) { | ||
| return new this(...(args.reverse() as [...T3, Web3ContextObject])); | ||
| } | ||
|
|
||
| public getContextObject(): Web3ContextObject<API, RegisteredSubs> { | ||
| public getContextObject(): Web3ContextObject<API | any, RegisteredSubs> { | ||
| return { | ||
| config: this.getConfig(), | ||
| provider: this.provider, | ||
|
|
@@ -201,7 +201,7 @@ export class Web3Context< | |
| * and then use it to create new objects of any type extended by `Web3Context`. | ||
| */ | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| public use<T extends Web3Context<any>, T2 extends unknown[]>( | ||
| public use<T extends Web3Context, T2 extends unknown[]>( | ||
| ContextRef: Web3ContextConstructor<T, T2>, | ||
| ...args: [...T2] | ||
| ) { | ||
|
|
@@ -220,7 +220,7 @@ export class Web3Context< | |
| /** | ||
| * Link current context to another context. | ||
| */ | ||
| public link<T extends Web3Context<API, RegisteredSubs>>(parentContext: T) { | ||
| public link<T extends Web3Context>(parentContext: T) { | ||
|
Comment on lines
-223
to
+220
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
which gives us type safety like so: Removing which means TypeScript is no longer aware of what's available for the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, export class Web3RequestManager<
API extends Web3APISpec = EthExecutionAPI,
> extends Web3EventEmitter<{
[key in Web3RequestManagerEvent]: SupportedProviders<API> | undefined;
}> {
...And so the safe typing is working well: And, if I provided no
So, I think you just had a cashing problem when checking out this branch. Kindly try again by running And let me know, please, if there is any type-safe feature that is not working as expected.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The third screenshot is the inferred type when using the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the plugin writer would like to use And then all the type-safety for the request manager would work inside the plugin. However, I also I caught the source of confusion for And is that the type of So, I pushed a commit that addresses those points in addition to a few enhancements....
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yea I was totally thinking about
export type FooApi = {
foo_bar: (arg1: string, arg2: number) => boolean;
bar_foo: () => string;
}
const web3Context = new Web3Context<FooApi>('http://127.0.0.1:8545');
web3Context.requestManager.send({
method: 'foo_bar',
params: [] // This errors as expected (see screenshot)
})
web3Context.requestManager.send({
method: 'bar_foo',
params: []
})The error I was actually seeing is fixed by extending export type ChainlinkPluginAPI = EthExecutionAPI & {
getPrice: () => Promise<Price>;
};Even though this interface Price {
roundId: string;
answer: string;
startedAt: string;
updatedAt: string;
answeredInRound: string;
}
interface ChainlinkPluginAPI extends Web3APISpec {
getPrice: () => Promise<Price>;
}
declare module 'web3/dist/web3' {
interface Web3 {
chainlink: ChainlinkPluginAPI;
}
}
export class ChainlinkPlugin extends Web3PluginBase<Web3APISpec> {
public pluginNamespace = 'chainlink';
protected readonly _contract: Contract<typeof AggregatorV3InterfaceABI>;
public constructor(abi: ContractAbi, address: Address) {
super();
this._contract = new Contract(abi, address);
}
public async getPrice() {
if (this._contract.currentProvider === undefined) this._contract.link(this);
return this._contract.methods.latestRoundData().call();
}
}You receive the following error for the line if (this._contract.currentProvider === undefined) this._contract.link(this);Argument of type 'this' is not assignable to parameter of type 'Web3Context<EthExecutionAPI, { logs: typeof LogsSubscription; newHeads: typeof NewHeadsSubscription; newBlockHeaders: typeof NewHeadsSubscription; }>'.
Type 'ChainlinkPlugin' is not assignable to type 'Web3Context<EthExecutionAPI, { logs: typeof LogsSubscription; newHeads: typeof NewHeadsSubscription; newBlockHeaders: typeof NewHeadsSubscription; }>'.
Types of property '_requestManager' are incompatible.
Type 'Web3RequestManager<ChainlinkPluginAPI>' is not assignable to type 'Web3RequestManager<EthExecutionAPI>'.
Type 'ChainlinkPluginAPI' is missing the following properties from type 'EthExecutionAPI': eth_getBlockByHash, eth_getBlockByNumber, eth_getBlockTransactionCountByHash, eth_getBlockTransactionCountByNumber, and 44 more.ts(2345)I was thinking
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great @spacesailor24 👍 And so it is time to merge this MR. However, because I think that, there are some copied ideas from this MR to #5393 (and this is also the reason for having conflicts in the MR with the destination branch). I suggest you do one of the following:
And by the way, I also pushed some more enhancements and comments to the code so when someone later would implement a plugin would have a clearer understanding, I hope. And this included 2 classes |
||
| this.setConfig(parentContext.getConfig()); | ||
| this._requestManager = parentContext.requestManager; | ||
| this.provider = parentContext.provider; | ||
|
|
||





Uh oh!
There was an error while loading. Please reload this page.