Skip to content

Need a dummy overload to improve inference #39850

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
stephanedr opened this issue Jul 31, 2020 · 1 comment
Open

Need a dummy overload to improve inference #39850

stephanedr opened this issue Jul 31, 2020 · 1 comment
Labels
Bug A bug in TypeScript
Milestone

Comments

@stephanedr
Copy link

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

Search Terms: dummy fake overload infer

Code

class FieldEvent<T extends Field> {
    constructor(readonly field: T, readonly message: string) { }
}

class Field {
    listen<T extends FieldEvent<Field>>(type: new (...args: any[]) => T, listener: (event: T) => void): void { }
}

class BeforeSetEvent<T extends number | string> extends FieldEvent<ValueField<T>> {
    constructor(field: ValueField<T>, public newValue: T) { super(field, ""); }
}

class AfterSetEvent<T extends number | string> extends FieldEvent<ValueField<T>> {
    constructor(field: ValueField<T>, readonly oldValue: T) { super(field, ""); }
}

class ValueField<T extends number | string> extends Field {
    constructor(public value: 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<U extends FieldEvent<Field>>(type: new (...args: any[]) => U, listener: (event: U) => void): void {
        super.listen(type, listener);
    }
}

let field = new ValueField(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.

@RyanCavanaugh
Copy link
Member

I'm not really sure if this is a "bug" per se, but agree that it's not ideal. A straightforward fix without worse side effects may not exist

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript
Projects
None yet
Development

No branches or pull requests

2 participants