You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
What if you wanted to write a function that box'd a list converted from an array? Ideally you could write the following:
compose(arrayToList,box)
and you'd get the type <T>(xs: T[]) => { value: List<T> }
Today the problem is that when our inference process sees no inferences for a type parameter, it infers its upper bound (which is implicitly {}).
Instead, what you really want to do is see that there are free type variables that are captured in the output, and attach them to the output type.
Starting off with this idea comes close. You get <T, U>(xs: T) => U, but of course, this doesn't propagate the original structures of inferences. Furthermore, T and U are unrelated. So what you want to do is unify the type variables during the first inference pass.
When you could do this is tough; you can't just replace the current inference process with unification. No telling what could break. But we can revisit that.
So saying "unification would do this" is fine, but how that happens is glossed over. There's some difficult cases.
A : T[]
B : List<T>, SomeOtherList<W>
C : W
Could say we only unify on named types.
What about object literal types?
It's a structural type system; y'can't backpedal on that.
Today we fix type parameters once they're requested in an anonymous function. How does this work with contextual typing?
Say it's there for single-signature types?
It's not about overloads.
Would we need to add type variables for anonymous functions?
We erred on the safe side much of the time to say that signatures had to be identical.
In the last release, we expanded this to have signatures that totally subsumed other signatures available to callers.
When we unified JSX logic with call resolution logic, React users got broken because we were more permissive in React.
Okay, so we methods available a lot of the time when you have two union types; however, it doesn't work great for methods that take callbacks.
For example, if you have xs: string[] | number[], trying to call xs.forEach is possible, but lambda functions don't undergo contextual typing (one of our inference processes).
The reason why is that the contextual type is something like ((x: string) => void) & ((y: number) => void).
You'd think that would be fine and in xs.forEach(a => a), a would have the type string | number, but what instead happens is that ((x: string) => void) & ((y: number) => void) forms something that looks like an overload list, and lambdas aren't contextually typed by overloads.
Three solutions:
Change contextual typing to be contextually typed by overload lists.
Could come up with an underlying "intersection signature" (we have something similar for unions).
Means there's a difference between contextual typing and relationship checking.
Control Flow Analysis for Destructuring Assignments
#28792
And this holds for any level of nesting.
And the same for object pattern assignments
Unification
Consider
What if you wanted to write a function that
box
'd a list converted from an array? Ideally you could write the following:and you'd get the type
<T>(xs: T[]) => { value: List<T> }
{}
).<T, U>(xs: T) => U
, but of course, this doesn't propagate the original structures of inferences. Furthermore,T
andU
are unrelated. So what you want to do is unify the type variables during the first inference pass.When you could do this is tough; you can't just replace the current inference process with unification. No telling what could break. But we can revisit that.
So saying "unification would do this" is fine, but how that happens is glossed over. There's some difficult cases.
Could say we only unify on named types.
Today we fix type parameters once they're requested in an anonymous function. How does this work with contextual typing?
Say it's there for single-signature types?
Would we need to add type variables for anonymous functions?
Also, building up constraints could get gross:
Could defer things.
The type might look gross for users.
{ get(): T }
is not so bad, but imagine a more complex function body.When you you're editing, what happens when the anonymous function comes first?
Seems like there's a lot of open questions.
Call signatures on union types
#7294
#29011
xs: string[] | number[]
, trying to callxs.forEach
is possible, but lambda functions don't undergo contextual typing (one of our inference processes).((x: string) => void) & ((y: number) => void)
.xs.forEach(a => a)
,a
would have the typestring | number
, but what instead happens is that((x: string) => void) & ((y: number) => void)
forms something that looks like an overload list, and lambdas aren't contextually typed by overloads.forEach
case is still broken, but at least we're better.never
parameters from these "synthesized" signatures?The text was updated successfully, but these errors were encountered: