Exhaustiveness checking with runtime error and assertNever#3599
Open
whilenot-dev wants to merge 2 commits into
Open
Exhaustiveness checking with runtime error and assertNever#3599whilenot-dev wants to merge 2 commits into
whilenot-dev wants to merge 2 commits into
Conversation
Author
|
@microsoft-github-policy-service agree |
This file contains hidden or 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
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.
The example function
getAreain the documentation on exhaustiveness checking currently creates a conflicting behavior between compile time and run time:The advantage of catching errors during compilation with help of the
never-type can only occur if the missing type (Triangle) is known and has already been implemented to be a variant of typeShape. While this is a helpful check during compilation, it can lead to false assumptions on the behavior at runtime.Where the cases
"circle"and"square"would both return a value of typenumberback to the caller, thedefaultcase currently would just fall back to returning the input argument of an "unknown" variant of typeShape, e.g.Triangle. Such a practice could lead to problems in other parts of the code base at runtime, depending on where theShape-objects are originating from.In practice, it is likely that objects of type
Shapeare members of response objects from API calls or any other IO results, so our type implementation oftype Shape = Circle | Squaremight just be mirroring an expectation of these response-/result-objects. We might not be in charge of their design and are merely a consuming client process. In such cases we might have an outdated implementation running that will actually fall back to the currentdefaultcase at runtime, returning a "yet unknown" object of typeTriangleback to its caller.This caller has been implemented to expect a value of type
number, as backed by static type checking, so any further algebraic operation on that return value (+,-,*,/etc.) would then throw a runtime error in parts of the code base that shouldn't worry about such a mistake in the first place.Therefor, it'd be a better practice to throw an explicit runtime error in such a case. Python has assert_never for exactly these occasions.
My proposal is to change the example slightly by throwing a runtime error as fallback in the
defaultcase with the help of a function calledassertNever: