Skip to content

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

Closed
@AnyhowStep

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.

Metadata

Metadata

Assignees

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