Skip to content

Need a dummy overload to improve inference #39850

Description

@stephanedr

TypeScript Version: 3.x, 4.0.0-beta, nightly

Search Terms: dummy fake overload infer

Code

classFieldEvent<TextendsField>{constructor(readonlyfield: T,readonlymessage: string){}}classField{listen<TextendsFieldEvent<Field>>(type: new(...args: any[])=>T,listener: (event: T)=>void): void{}}classBeforeSetEvent<Textendsnumber|string>extendsFieldEvent<ValueField<T>>{constructor(field: ValueField<T>,publicnewValue: T){super(field,"");}}classAfterSetEvent<Textendsnumber|string>extendsFieldEvent<ValueField<T>>{constructor(field: ValueField<T>,readonlyoldValue: T){super(field,"");}}classValueField<Textendsnumber|string>extendsField{constructor(publicvalue: T){super();}// listen<U extends FieldEvent<Field>>(type: new (arg: this) => U, listener: (event: U) => void): void;// listen<U extends FieldEvent<Field>>(type: new (...args: any[]) => U, listener: (event: U) => void): void;listen<UextendsFieldEvent<Field>>(type: new(...args: any[])=>U,listener: (event: U)=>void): void{super.listen(type,listener);}}letfield=newValueField(0);field.listen(FieldEvent,(event)=>event.field);// event: FieldEvent<any>field.listen(BeforeSetEvent,(event)=>{event.field;event.newValue;});// event: BeforeSetEvent<any>field.listen(AfterSetEvent,(event)=>{event.field;event.oldValue;});// event: AfterSetEvent<any>

Expected behavior:
event to be better inferred than any.

Actual behavior:
event inferred as any.

But if we uncomment the 2 overloads, then event is correctly inferred:

field.listen(FieldEvent, (event) => event.field); // event: FieldEvent<ValueField<0>>
field.listen(BeforeSetEvent, (event) => { event.field; event.newValue; }); // event: BeforeSetEvent<0>
field.listen(AfterSetEvent, (event) => { event.field; event.oldValue; }); // event: AfterSetEvent<0>

What's surprising (so the reason I consider it as a bug):

  • The 1st overload doesn't match any signature.
  • But it influences the way the other overload is inferred.

Note that if we replace (arg: this) by () or another type, then:

field.listen(FieldEvent, (event) => event.field); // event: FieldEvent<Field>
field.listen(BeforeSetEvent, (event) => { event.field; event.newValue; }); // event: BeforeSetEvent<string | number>
field.listen(AfterSetEvent, (event) => { event.field; event.oldValue; }); // event: AfterSetEvent<string | number>

Playground Link:Playground Link

Related Issues: I first posted #36226 but was not able to solve my issue, until I found the (arg: this) trick.

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugA bug in TypeScriptDomain: check: Type InferenceRelated to type inference performed during signature resolution or `infer` type resolution

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions