Skip to content

Generic function with rest parameter assignability not transitive #32948

@AnyhowStep

Description

@AnyhowStep

TypeScript Version:

Search Terms:

Code

/**
 * --strictFunctionTypes
 */

export type ExtendedMapper<HandledInputT, OutputT, ArgsT extends any[]> = (
    (name : string, mixed : HandledInputT, ...args : ArgsT) => OutputT
);

//type a = (name: string, mixed: any, args_0: any) => any
type a = ExtendedMapper<any, any, [any]>;
//type b = (name: string, mixed: any, ...args: any[]) => any
type b = ExtendedMapper<any, any, any[]>;
//3.5.1, [email protected]
//Expected: "y"
//Actual  : "y"
//https://github.com/microsoft/TypeScript/pull/32924#issuecomment-521819476
//https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/40404/artifacts?artifactName=tgz&fileId=AD9D22CF70561BEAF5758E061B61D3FF891ADF664E37C532F5881393CE7DC83202&fileName=/typescript-3.7.0-insiders.20190815.tgz
//Expected: "y"
//Actual  : "n" <-- Intentional?
type test = a extends b ? "y" : "n"

type a2 = (name: string, mixed: any, args_0: any) => any
type b2 = (name: string, mixed: any, ...args: any[]) => any
//3.5.1, [email protected]
//Expected: "y"
//Actual  : "y"
//https://github.com/microsoft/TypeScript/pull/32924#issuecomment-521819476
//https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/40404/artifacts?artifactName=tgz&fileId=AD9D22CF70561BEAF5758E061B61D3FF891ADF664E37C532F5881393CE7DC83202&fileName=/typescript-3.7.0-insiders.20190815.tgz
//Expected: "y"
//Actual  : "y"
type test2 = a2 extends b2 ? "y" : "n"

//a extends b2 extends b
//However, a DOES NOT extend b
//It seems assignability is not transitive...

//"y" for all versions
type aExtendsB2 = a extends b2 ? "y" : "n"
//"y" for all versions
type b2ExtendsB = b2 extends b ? "y" : "n"

type TakeExtendedMapperRest<MapperT extends b> = (
    ["Blah", MapperT]
);

//Works in 3.5.1
//Fails for https://github.com/microsoft/TypeScript/pull/32924#issuecomment-521819476
export type ShouldWorkButFails<T extends a> = (
    //Type 'ExtendedMapper<any, any, [any]>' does not satisfy the constraint 'ExtendedMapper<any, any, any[]>'.
    //  Property '0' is missing in type 'any[]' but required in type '[any]'.ts(2344)
    //a -> b not allowed
    TakeExtendedMapperRest<T>
    //                     ~
);

//Works in 3.5.1
//Works in https://github.com/microsoft/TypeScript/pull/32924#issuecomment-521819476
export type Workaround<T extends a> = (
    TakeExtendedMapperRest<
        //OK!
        //Takes advantage of a -> b2 -> b being allowed
        Extract<T, b2>
    >
);

//Works in 3.5.1
//Fails in https://github.com/microsoft/TypeScript/pull/32924#issuecomment-521819476
type WorkaroundTest = TakeExtendedMapperRest<a>;

//Works in 3.5.1
//Works in https://github.com/microsoft/TypeScript/pull/32924#issuecomment-521819476
//type WorkaroundTest2 = ["Blah", ExtendedMapper<any, any, [any]>]
type WorkaroundTest2 = Workaround<a>; //Success

Expected behavior:

Build in #32924 (comment) should behave the same as 3.5.1 and [email protected]

Assignability should be transitive.

a -> b2 -> b should imply a -> b

Actual behavior:

Assignability is not transitive

a -> b2 -> b but not a -> b

Playground Link:
Playground

Related Issues:

#32924 (comment)

#32924 (comment)

#32924 (comment)

I'm not sure which commit introduced this problem.

@weswigham

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScriptFix AvailableA PR has been opened for this issue

Type

No type
No fields configured for issues without a type.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions