Skip to content
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

Typescript 3.4 breaks some type inference with method overloads. (unknown) #36735

Closed
garronej opened this issue Feb 11, 2020 · 5 comments
Closed
Labels
Question An issue which isn't directly actionable in code

Comments

@garronej
Copy link

garronej commented Feb 11, 2020

TypeScript Version: 3.4 and up

Search Terms:
unknown, 3.4, type inference fails, method overload

Code

type Circle = {
    type: "CIRCLE";
    radius: number;
};

type Square = {
    type: "SQUARE";
    sideLength: number;
};

type Shape = Circle | Square;


class Evt<T> {

    public attach<U>(
        matcher: (data: T)=> [U] | undefined,
        callback: (transformedData: U)=> void
    ): Promise<U>;
    public attach(
        matcher: (data: T) => boolean,
        callback: (data: T) => void
    ): Promise<T>;
    public attach(...args: any[]){
        return null as any;
    }

}

const evtShape = new Evt<Shape>();

//OK
const prRadius = evtShape.attach(
    shape => shape.type === "CIRCLE" ? [shape.radius] : undefined,
    radius => { }
);


const prShape = evtShape.attach(
    shape => true,
    shape => { } //<====== In typescript 3.4 and up shape is unknown 
);

Expected behavior:

In the last line, shape should be of type Shape. In typescript 3.4 and up it is of type unknown.

Actual behavior:

Playground Link

@DanielRosenwasser DanielRosenwasser added the Needs Investigation This issue needs a team member to investigate its status. label Feb 11, 2020
@DanielRosenwasser
Copy link
Member

DanielRosenwasser commented Feb 11, 2020

Slightly shorter

declare class Stream<T> {
    compactAndThen<U>(matcher: (data: T) => [U] | undefined, callback: (transformedData: U) => void): Promise<U>;
    compactAndThen(matcher: (data: T) => boolean, callback: (data: T) => void): Promise<T>;
}

const thing = new Stream<string>();

//OK
const prRadius = thing.compactAndThen(
    str => str.length > 0 ? [str.toLowerCase()] : undefined,
    str => { }
);


const prShape = thing.compactAndThen(
    foo => true,
    bar => { } //<====== In typescript 3.4+, 'bar' is unknown 
);

Looks like bar gets unknown due to no inferences from the first overload. Not sure if there's a way to fix this. @ahejlsberg?

@garronej
Copy link
Author

garronej commented Feb 13, 2020

After further investigation, I noticed that event in typescript prior to 3.4 altho the type Shape is inferred it can only be used as a {}.

Screenshot 2020-02-13 at 08 54 42

Screenshot 2020-02-13 at 08 50 43

Thanks to the typescript's team, you guys do amazing work <3

@garronej
Copy link
Author

garronej commented Apr 9, 2020

Hello,
Just a quick update to say that this limitation is a big deal for the library I am working on: EVT.
The overload of the "attach" method had to be split into two groups "attach" and "$attach" and peoples get confused about why and when they need to add the "$".
I know this is really pushing the already amazing type inference system but it would be great for EVT to be able to merge all the overload together.

Regards

@ahejlsberg
Copy link
Member

ahejlsberg commented Apr 21, 2020

The two overloads are just too close for us to distinguish between them. Best alternative I can come up with is a single signature that uses a conditional type:

declare class Stream<T> {
    compactAndThen<U extends [any] | boolean>(matcher: (data: T) => U | undefined, callback: (data: U extends [infer V] ? V : T) => void): Promise<U extends [infer V] ? V : T>;
}

This seems to deliver the desired results.

@ahejlsberg ahejlsberg added Question An issue which isn't directly actionable in code and removed Needs Investigation This issue needs a team member to investigate its status. labels Apr 21, 2020
@ahejlsberg ahejlsberg removed this from the TypeScript 3.9.1 milestone Apr 21, 2020
@ahejlsberg ahejlsberg removed their assignment Apr 21, 2020
@garronej
Copy link
Author

garronej commented Apr 22, 2020

@ahejlsberg Thank you very much for taking the time to come out with a workaround, it is very clever.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

3 participants