Skip to content

[Regression] ReturnType<> Inference works on 3.3.3, breaks on 3.4.1, 3.5.1 #31814

Description

@AnyhowStep

TypeScript Version: 3.4.1, 3.5.1

Search Terms: regression, ReturnType, parameter, inference

Code

interface Mapper<HandledInputT, OutputT> {
    (name : string, mixed : HandledInputT) : OutputT,
}


export type IsPipeable<
    FromF extends Mapper<any, any>,
    ToF extends Mapper<any, any>
> = (
    ToF extends Mapper<infer HandledInputT, any> ?
    (
        ReturnType<FromF> extends HandledInputT ?
        true :
        false
    ) :
    false
);

export type AssertPipeable<
    FromF extends Mapper<any, any>,
    ToF extends Mapper<any, any>
> = (
    IsPipeable<FromF, ToF> extends true ?
    ToF :
    [ReturnType<FromF>, "is not pipeable"]
);

declare function pipe<
    F0 extends Mapper<unknown, any>,
    F1 extends Mapper<any, any>
> (
    f0 : F0,
    f1 : AssertPipeable<F0, F1>
): void;

declare function literal<ArrT extends (string | number | boolean | bigint | null | undefined)[]>(
    ...arr: ArrT
): (
    Mapper<unknown, ArrT[Extract<keyof ArrT, number>]>
);
declare const b: Mapper<"0" | "1" | 0 | 1 | "false" | "true", boolean>

//TS suddenly thinks the first arg is Mapper<unknown, any>.
//It is actually Mapper<unknown, "0" | "1" | 0 | 1 | "false" | "true">.
pipe(
    //TS knows this is Mapper<unknown, "0" | "1" | 0 | 1 | "false" | "true">
    literal("0", "1", 0, 1, "false", "true"),
    /*
        Expected: works.
        Actual:
        Argument of type 'Mapper<0 | "0" | "1" | 1 | "false" | "true", boolean>'
        is not assignable to parameter of type '[any, "is not pipeable"]'.

        Succeeds with 3.3.3,
        Fails with 3.4.1,
        Fails with 3.5.1
    */
    b
);

const a = literal("0", "1", 0, 1, "false", "true");
//TS now knows the first arg is Mapper<unknown, "0" | "1" | 0 | 1 | "false" | "true">
pipe(
    a,
    /*
        This works.
        `a` is literally the same type as
        `literal("0", "1", 0, 1, "false", "true")`.

        Why would the first pipe() call fail,
        but the second one succeed?

        Succeeds with 3.3.3,
        Succeeds with 3.4.1,
        Succeeds with 3.5.1
    */
    b
);

Expected behavior:

The below should work,

pipe(
    literal("0", "1", 0, 1, "false", "true"),
    b
);

Actual behavior:

It used to work but does not work now.

Playground Link: Playground

Related Issues:

I feel like it is related to #29133 somehow. Because I have ReturnType<> being used in a parameter again. But it's somewhat different this time in that the first argument is not an anonymous function "literal" I created. It's a function given by another function.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Working as IntendedThe behavior described is the intended behavior; this is not a bug

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions