-
-
Notifications
You must be signed in to change notification settings - Fork 201
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[json-rpc-engine] Fix any types in catch blocks, refactor #3906
Conversation
70119ee
to
c59d1b1
Compare
ca41d02
to
58949ad
Compare
28b21db
to
c81e0cc
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left some minor comments but overall this looks good. Would be great to address these type issues as they seem to be multiplying, but that seems like another can of worms 😅
return handlerCallback(error); | ||
} catch (error) { | ||
// TODO: Explicitly handle errors thrown from `#runReturnHandlers` that are not of type `JsonRpcEngineCallbackError` | ||
return handlerCallback(error as JsonRpcEngineCallbackError); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of interest, do we need to change the type of the error
argument? That seems to necessitate adding a type assertion here, so we'd now be lying about the type of this error. I just want to make sure: do we think that this is preferable to using any
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On second glance, the error is being thrown by #runReturnHandlers
, which is guaranteed to throw SerializableJsonRpcError | Error
. Removed the assertion and added a comment explaining why: 4b61631
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All of the other type assertions with TODOs are end()
calls.
With these, I think it doesn't make sense to inaccurately force error
into the JsonRpcEngineCallbackError
type when the test specs are passing in all error objects thrown by middleware into end
callbacks regardless of their type.
IMO whatever type safety gains we get from narrowing the error type from unknown
are cancelled out by the fact that we have to use inaccurate type assertions everywhere to make the narrower type constraint work.
I widened JsonRpcEngineCallback
's error
param to unknown
, which lets us remove the TODO comments and the type assertions. What do you think? Would this be a regression in terms of type safety or too disruptive to downstream code?
bac8e0e b9549ed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these changes look better overall and make more sense than the previous changes.
1df21c3
to
ed282d8
Compare
…own` and remove now unnecessary narrowing branches
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I attempted a new approach of replacing all JsonRpcEngineCallbackError
with unknown
.
This cuts down on the diffs, makes a lot of the types consistent with how they're used in the tests, makes a lot of assertions unnecessary, and brings coverage back up to 100%.
I think this might be an appropriate scope for the current PR's objective (fix any). Implementing consistent usage of JsonRpcEngineCallbackError
for the middleware callbacks should probably be handled in its own initiative.
|
||
export type JsonRpcEngineCallbackError = Error | SerializedJsonRpcError | null; | ||
|
||
export type JsonRpcEngineReturnHandler = ( | ||
done: (error?: JsonRpcEngineCallbackError) => void, | ||
done: (error?: unknown) => void, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New strategy: consistently type all errors as unknown
.
export type JsonRpcEngineEndCallback = ( | ||
error?: JsonRpcEngineCallbackError, | ||
) => void; | ||
export type JsonRpcEngineEndCallback = (error?: unknown) => void; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New strategy: consistently type all errors as unknown
.
hasProperty, | ||
isJsonRpcNotification, | ||
isJsonRpcRequest, | ||
} from '@metamask/utils'; | ||
|
||
export type JsonRpcEngineCallbackError = Error | SerializedJsonRpcError | null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JsonRpcEngineCallbackError
is no longer used anywhere in core or extension. Mobile has two instances in RPCMethodMiddleware.ts
.
@@ -18,7 +21,7 @@ export type AsyncJsonrpcMiddleware< | |||
next: AsyncJsonRpcEngineNextCallback, | |||
) => Promise<void>; | |||
|
|||
type ReturnHandlerCallback = (error: null | Error) => void; | |||
type ReturnHandlerCallback = Parameters<JsonRpcEngineReturnHandler>[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This definition is responsive to changes in JsonRpcEngineReturnHandler
.
@@ -317,8 +328,8 @@ export class JsonRpcEngine extends SafeEventEmitter { | |||
) | |||
).filter( | |||
// Filter out any notification responses. | |||
(response) => response !== undefined, | |||
) as JsonRpcResponse<Json>[]; | |||
(response): response is JsonRpcResponse<Json> => response !== undefined, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Good example usage of this.
| (JsonRpcRequest | JsonRpcNotification)[] | ||
| JsonRpcRequest | ||
| JsonRpcNotification, | ||
callback?: (error: unknown, response: never) => void, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
never
is used to widen the implementation signature enough to be compatible with all of the overload signatures.
isJsonRpcNotification(callerReq) && | ||
!isJsonRpcRequest(callerReq) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isJsonRpcNotification
alone doesn't narrow callerReq
to JsonRpcNotification
.
// This assertion is safe because of the runtime checks validating that `req` is an array and `callback` is defined. | ||
// There is only one overload signature that satisfies both conditions, and its `callback` type is the one that's being asserted. | ||
callback as ( | ||
error: unknown, | ||
responses?: JsonRpcResponse<Json>[], | ||
) => void, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally, TypeScript would have better pattern-matching around overload signatures and would be capable of narrowing callback
and responses
so that this assertion is unnecessary.
return this.#handle(req as JsonRpcRequest, callback); | ||
return this.#handle( | ||
req, | ||
callback as (error: unknown, response?: JsonRpcResponse<Json>) => void, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first and second overload signatures of handle
are the only cases where req
is a non-array and callback
is defined. This is assertion is safe for those overload signatures.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just had one more comment, but this otherwise looks good to me.
const parsedError = error || response.error; | ||
if (parsedError) { | ||
response.error = serializeError(parsedError); | ||
} | ||
// True indicates that the request should end | ||
resolve([parsedError, true]); | ||
resolve([parsedError ?? null, true]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that we are converting undefined
to null
here. This could matter, so what do you think about this:
const parsedError = error || response.error; | |
if (parsedError) { | |
response.error = serializeError(parsedError); | |
} | |
// True indicates that the request should end | |
resolve([parsedError, true]); | |
resolve([parsedError ?? null, true]); | |
const parsedError: unknown = error || response.error; | |
if (parsedError) { | |
response.error = serializeError(parsedError); | |
} | |
// True indicates that the request should end | |
resolve([parsedError, true]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for catching this. It's no longer necessary now that JsonRpcEngineCallbackError
is not being used here.
Applied here: cfaa18b, except I didn't add the : unknown
annotation because {}
is NonNullable<unknown>
, meaning unknown
would pollute parsedError
's type signature with a null
that previously wasn't there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Everything looks good to me now. Nice work!
Explanation
any
usage in theJsonRpcEngine
class.unknown
to reflect actual usage in consumers and tests. -JsonRpcEngineCallbackError
is no longer used within the package.References
json-rpc-engine
: Replace use ofany
with proper types (non-test files only) #3720Changelog
@metamask/json-rpc-engine
error
parameters inJsonRpcEngineReturnHandler
,JsonRpcEngineNextCallback
, andJsonRpcEngineEndCallback
are widened fromJsonRpcEngineCallbackError
tounknown
.Checklist