-
-
Notifications
You must be signed in to change notification settings - Fork 96
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
Fix contradictory typing of IFrameMessageResponse
and refactor into modular types
#207
Merged
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
MajorLift
force-pushed
the
231026-typing-fix-iframemessageresponse
branch
from
October 26, 2023 20:05
7e8760d
to
d868b03
Compare
MajorLift
changed the title
Make
Fix contradictory typing for Oct 26, 2023
IFrameMessageResponse
non-genericIFrameMessageResponse
and refactor for modularity, maintainability
MajorLift
changed the title
Fix contradictory typing for
Fix contradictory typing of Oct 26, 2023
IFrameMessageResponse
and refactor for modularity, maintainabilityIFrameMessageResponse
and refactor for modularity, maintainability
MajorLift
changed the title
Fix contradictory typing of
Fix contradictory typing of Oct 26, 2023
IFrameMessageResponse
and refactor for modularity, maintainabilityIFrameMessageResponse
and refactor into modular types
- `TAction` generic parameter is constrained as a subtype of `IFrameMessageAction` and `IFrameMessageResponse` is only being narrowed, not widened.
…erent/missing properties
MajorLift
force-pushed
the
231026-typing-fix-iframemessageresponse
branch
from
October 27, 2023 04:19
65ba771
to
c2a051f
Compare
mcmire
reviewed
Nov 2, 2023
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.
Overall these changes look great and make sense! I just had some suggestions below.
Co-authored-by: Elliot Winkler <[email protected]>
…avoid confusion regarding atypically-shaped `IFrameMessageResponse` types Co-authored-by: Elliot Winkler <[email protected]>
MajorLift
force-pushed
the
231026-typing-fix-iframemessageresponse
branch
from
November 7, 2023 16:28
01f704a
to
9307a30
Compare
mcmire
approved these changes
Nov 7, 2023
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.
Looks good!
legobeat
added a commit
to legobeat/eth-ledger-bridge-keyring
that referenced
this pull request
Dec 2, 2023
…tor into modular types (MetaMask#207)" This reverts commit 2f0da8f.
Merged
legobeat
pushed a commit
to legobeat/eth-ledger-bridge-keyring
that referenced
this pull request
Dec 3, 2023
… modular types (MetaMask#207) ## Motivation `IFrameMessageResponse` is currently defined with a generic parameter `TAction`. This parameter doesn't usefully narrow or widen the type. - The `action: TAction` property appears to *widen* `IFrameMessageResponse` to accept any action type, but `TAction` is also constrained as a subtype of `IFrameMessageActions`. - The `TAction` generic param appears to *narrow* `IFrameMessageResponse` to select individual union members, but it interferes with the inference-based type narrowing we can get if `IFrameMessageResponse` is an exhaustively enumerated discriminated union. This causes two problems: 1. Type errors on assignment operations that should be valid. - e.g. [`as` type casting](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/207/files#diff-c901ebd8641651c9156a86894574a6d9567f2ae79495de0edff2cbef8ae958f0L302-L304) is necessary here because supertype is being assigned to a subtype i.e. `(response: IFrameMessageResponse<TAction>) => void` to `(response: IFrameMessageResponse<IFrameMessageActions>) => void`. - In general, `(x: SuperType) => T` is a *subtype* of `(x: SubType) => T`. - **This error indicates an underlying issue with the typing and shouldn't be suppressed.** - Removing `TAction` puts `(response: SomeIFrameMessageResponse) => void` on the LHS (assignee, supertype) and `(response: IFrameMessageResponse) => void` on the RHS (assigned, subtype), resolving this logical error. 2. `TAction` is also silencing type errors we should be getting from type narrowing based on `action` value. - e.g. Some union members of `IFrameMessageResponse` do not include a `success`, `error`, `payload`, or `payload.error` property, but because of `TAction`, TypeScript doesn't alert us that we should be performing `in` checks on them in addition to null checks. - This can cause unexpected failure at runtime, especially from the destructuring assignments that are being used. Constraining `IFrameMessageResponse['action']` to `IFrameMessageActions` both resolves these issues and guides us towards writing type-safe logic about these actions that conform to their specific type signatures. It appears that this was the original intention of writing `IFrameMessageActions` as a discriminated union instead of a wider type encompassing all possible actions. ## Changes - **BREAKING** Narrows `IFrameMessageResponse` type definition ## Explanation - To resolve these issues, This PR makes `IFrameMessageResponse` non-generic and removes `as` casting. - For improved readability and maintainability, `IFrameMessageResponse` is also refactored into a union of named types. - A `IFrameMessageResponseBase` type is defined for modularity and better visibility of `IFrameMessageResponse` types with atypical shapes. ## References - Closes MetaMask#208 - More info on function subtyping: MetaMask/core#1890 (comment)
Merged
2 tasks
legobeat
pushed a commit
to legobeat/eth-ledger-bridge-keyring
that referenced
this pull request
Dec 4, 2023
… modular types (MetaMask#207) ## Motivation `IFrameMessageResponse` is currently defined with a generic parameter `TAction`. This parameter doesn't usefully narrow or widen the type. - The `action: TAction` property appears to *widen* `IFrameMessageResponse` to accept any action type, but `TAction` is also constrained as a subtype of `IFrameMessageActions`. - The `TAction` generic param appears to *narrow* `IFrameMessageResponse` to select individual union members, but it interferes with the inference-based type narrowing we can get if `IFrameMessageResponse` is an exhaustively enumerated discriminated union. This causes two problems: 1. Type errors on assignment operations that should be valid. - e.g. [`as` type casting](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/207/files#diff-c901ebd8641651c9156a86894574a6d9567f2ae79495de0edff2cbef8ae958f0L302-L304) is necessary here because supertype is being assigned to a subtype i.e. `(response: IFrameMessageResponse<TAction>) => void` to `(response: IFrameMessageResponse<IFrameMessageActions>) => void`. - In general, `(x: SuperType) => T` is a *subtype* of `(x: SubType) => T`. - **This error indicates an underlying issue with the typing and shouldn't be suppressed.** - Removing `TAction` puts `(response: SomeIFrameMessageResponse) => void` on the LHS (assignee, supertype) and `(response: IFrameMessageResponse) => void` on the RHS (assigned, subtype), resolving this logical error. 2. `TAction` is also silencing type errors we should be getting from type narrowing based on `action` value. - e.g. Some union members of `IFrameMessageResponse` do not include a `success`, `error`, `payload`, or `payload.error` property, but because of `TAction`, TypeScript doesn't alert us that we should be performing `in` checks on them in addition to null checks. - This can cause unexpected failure at runtime, especially from the destructuring assignments that are being used. Constraining `IFrameMessageResponse['action']` to `IFrameMessageActions` both resolves these issues and guides us towards writing type-safe logic about these actions that conform to their specific type signatures. It appears that this was the original intention of writing `IFrameMessageActions` as a discriminated union instead of a wider type encompassing all possible actions. ## Changes - **BREAKING** Narrows `IFrameMessageResponse` type definition ## Explanation - To resolve these issues, This PR makes `IFrameMessageResponse` non-generic and removes `as` casting. - For improved readability and maintainability, `IFrameMessageResponse` is also refactored into a union of named types. - A `IFrameMessageResponseBase` type is defined for modularity and better visibility of `IFrameMessageResponse` types with atypical shapes. ## References - Closes MetaMask#208 - More info on function subtyping: MetaMask/core#1890 (comment)
legobeat
added a commit
that referenced
this pull request
Dec 4, 2023
… modular types (#207) (#215) Co-authored-by: Jongsun Suh <[email protected]>
2 tasks
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Motivation
IFrameMessageResponse
is currently defined with a generic parameterTAction
. This parameter doesn't usefully narrow or widen the type.action: TAction
property appears to widenIFrameMessageResponse
to accept any action type, butTAction
is also constrained as a subtype ofIFrameMessageActions
.TAction
generic param appears to narrowIFrameMessageResponse
to select individual union members, but it interferes with the inference-based type narrowing we can get ifIFrameMessageResponse
is an exhaustively enumerated discriminated union.This causes two problems:
as
type casting is necessary here because supertype is being assigned to a subtype i.e.(response: IFrameMessageResponse<TAction>) => void
to(response: IFrameMessageResponse<IFrameMessageActions>) => void
.(x: SuperType) => T
is a subtype of(x: SubType) => T
.TAction
puts(response: SomeIFrameMessageResponse) => void
on the LHS (assignee, supertype) and(response: IFrameMessageResponse) => void
on the RHS (assigned, subtype), resolving this logical error.TAction
is also silencing type errors we should be getting from type narrowing based onaction
value.IFrameMessageResponse
do not include asuccess
,error
,payload
, orpayload.error
property, but because ofTAction
, TypeScript doesn't alert us that we should be performingin
checks on them in addition to null checks.Constraining
IFrameMessageResponse['action']
toIFrameMessageActions
both resolves these issues and guides us towards writing type-safe logic about these actions that conform to their specific type signatures. It appears that this was the original intention of writingIFrameMessageActions
as a discriminated union instead of a wider type encompassing all possible actions.Changes
IFrameMessageResponse
type definitionExplanation
IFrameMessageResponse
non-generic and removesas
casting.IFrameMessageResponse
is also refactored into a union of named types.IFrameMessageResponseBase
type is defined for modularity and better visibility ofIFrameMessageResponse
types with atypical shapes.References
IFrameMessageResponse
and refactor into modular types #208base-controller
] Fix allany
usage, apply universal supertype for functions core#1890 (comment)