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
JavaScript has very dynamic nature. Often library can only give imprecise typed API and let users annotate their code to give more specific types. However, given TypeScript's contextual typing spec, library API can lose typing information and requires user to annotate more code than necessary.
Example1. JQuery's XHR:
jQuery's XHR is deferred like object that has a then method. then method will be called with data fetched from server. This is the typing from @types/jquery
Some JavaScript libraries heavily depends on injecting this to user provided function. A classic example is jquery's event listening code.
And with #6739, TypeScript has great support to inject a typed this to function via contextual typing. However, when function's parameter is annotated, contextual typing is skipped.
A jQuery example.
$('div').input(function(e: JQueryClickEvent){varname=this.getAttribute('id');// this is typed any});
vue heavily depends on this injection for passing context to method definition. Supporting partial annotated function can help reducing explict this type annotation via a typed API. See #10461 (comment) for example.
VueTyped.data({a: 1}).method(function(this,n: number){// unannotated this can be typedthis.a+=n})
Example3. context injection in koa-route and redux
Some libraries will provide users functionality to specify their own handlers for different actions. For example, koa-route users can specify request handlers by app.get('path', handler). redux users can specify reducers (a handler to update state).
These handler declaration will all have a leading parameter such as context or state for handlers to access application state. And rest parameters will stand for arguments to trigger handlers.
// in koakoaApp.use(koaRoute.get('pet/:id',(ctx,id: number)=>{// ctx is any hereletrequest=ctx.request}))// in reduxconstreducer: Reducer=function(state,a: Action){// state is any here}
In some library, context type is computed by compiler, which isn't possible for user to manually annotate.
Context typing can be done by currying, but this is bad for API design and incurs unnecessary runtime overhead.
Proposal
We first to define what does partially annotated function mean.
A partially annotated function is a function expression that has no parameter or has at least one parameter missing type annotation.
No parameter is for compatibility like below.
interface A { contextualTypeThis(this: {a: number}): void }
var a: A = { contextualTypeThis: function() { this.a } }
To enable contextual typing on partially annotated function requires several modification to spec.
In a typed function call, argument expressions are contextually typed by their corresponding parameter types.
is changed to
In a typed function call, argument expressions are contextually typed by their corresponding parameter types, if not manually annotated. Otherwise the type of an argument expression is used to inferentially type its parameter type, if the parameter type can contain type parameters.
Note #4.15.2 is not changed. Namely these two rules:
(Type parameter inference) Proceeding from left to right, each argument expression e is inferentially typed by its corresponding parameter type P, possibly causing some inferred type arguments to become fixed....
And
When a function expression is inferentially typed (section 4.10) and a type assigned to a parameter in that expression references type parameters for which inferences are being made, the corresponding inferred type arguments to become fixed and no further candidate inferences are made for them.
In short, preceding arguments are inferred as if following arguments are not annotated.
Thus, this code will break.
Because R is inferred as {} in t, and T is inferred as {} accordingly. And because typeof t is assignable to {}, so result is typed as {}, ignoring users' annotation.
Compatiblity
This will introduce breaking changes. But I have no idea how will it impact real world code
A parameter used to be inferred as any will become inferred to some type. This is a breaking change.
The above example is also a breaking change, the return type is currently inferred as any.
Overloading resolution probably is not influenced because contextual typing will succeed for a unannotated argument.
Implementaion
I have a experimental branch for partial annotation, and some new tests (still needs a lot more). It seems modification to existing code is not massive.
The text was updated successfully, but these errors were encountered:
Background:
JavaScript has very dynamic nature. Often library can only give imprecise typed API and let users annotate their code to give more specific types. However, given TypeScript's contextual typing spec, library API can lose typing information and requires user to annotate more code than necessary.
Example1. JQuery's XHR:
jQuery's XHR is
deferred
like object that has athen
method.then
method will be called withdata
fetched from server. This is the typing from@types/jquery
Users will want to annotate
data
because they know what will be returned, but this will break contextual typing :Two alternatives, but both require more annotation
Similar examples can also be found in angularjs,
Example 2.
this
injection in jQuery and VueSome JavaScript libraries heavily depends on injecting
this
to user provided function. A classic example is jquery's event listening code.And with #6739, TypeScript has great support to inject a typed
this
to function via contextual typing. However, when function's parameter is annotated, contextual typing is skipped.A jQuery example.
vue heavily depends on
this
injection for passing context to method definition. Supporting partial annotated function can help reducing explict this type annotation via a typed API. See #10461 (comment) for example.Example3. context injection in koa-route and redux
Some libraries will provide users functionality to specify their own handlers for different actions. For example, koa-route users can specify request handlers by
app.get('path', handler)
. redux users can specify reducers (a handler to update state).These handler declaration will all have a leading parameter such as
context
orstate
for handlers to access application state. And rest parameters will stand for arguments to trigger handlers.In some library, context type is computed by compiler, which isn't possible for user to manually annotate.
Context typing can be done by currying, but this is bad for API design and incurs unnecessary runtime overhead.
Proposal
We first to define what does partially annotated function mean.
No parameter is for compatibility like below.
To enable contextual typing on partially annotated function requires several modification to spec.
In #4.10
is changed to
And in #4.23
is changed to
Note #4.15.2 is not changed. Namely these two rules:
And
In short, preceding arguments are inferred as if following arguments are not annotated.
Thus, this code will break.
Because
R
is inferred as{}
int
, andT
is inferred as{}
accordingly. And becausetypeof t
is assignable to{}
, so result is typed as{}
, ignoring users' annotation.Compatiblity
This will introduce breaking changes. But I have no idea how will it impact real world code
A parameter used to be inferred as
any
will become inferred to some type. This is a breaking change.The above example is also a breaking change, the return type is currently inferred as
any
.Overloading resolution probably is not influenced because contextual typing will succeed for a unannotated argument.
Implementaion
I have a experimental branch for partial annotation, and some new tests (still needs a lot more). It seems modification to existing code is not massive.
The text was updated successfully, but these errors were encountered: