Support helper-based type narrowing #10
Merged
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 level of complexity in helper signatures currently prohibits them from acting as type guards, which is especially problematic since templates don't have a native notion of equality, so you can't do the equivalent of ad-hoc
if (obj.discriminatorField === 'discriminant-value')
checks.This PR makes a few changes that, together, enable helpers to narrow the types of their arguments.
There are two things that prevent
isNumber
from narrowing the type ofmaybeANumber
. First, theReturnsValue
makes it impossible to represent avalue is number
at all, as suchis
clauses are restricted syntactically so that they can only be the direct return type of a function. Second, even with that solved, the wrappinginvokeInline
function would still degrade a type guard to a regularboolean
-returning function.The change in this PR eliminates the
ReturnsValue
macro, so that helpers are represented essentially as their raw function types. Pulling on the thread of that change, signatures as a whole can become much simpler, with theCreatesModifier
type becoming a plain marker object. TheInvokable<T>
wrapper andAnySignature
type both go away entirely, as they'd already been weakened nearly to the point of doing nothing and with this change they no longer deliver any value at all.Secondly, it eliminates
invokeInline
as a peer ofinvokeModifier
andinvokeBlock
. Instead,invokeEmit
now exists, but is only applied to values that will be emitted into the DOM either directly as content or into an attribute or concatenated string (which provides a bit of type safety against[object Object]
showing up on screen). In cases where the return value of a helper is actually treated as data, such as a component@arg
or a helper parameter, noinvoke
helper is required at all and the value is passed directly.Together, these changes make the snippet above into something more like: