Skip to content

Rest elements in generic tuple #26113

Closed

Description

@vmit

TypeScript Version: 3.1.0-dev.20180801

Search Terms: spread tuple

Code

interface Foo<ArgsT extends any[]> {}

interface Bar<SubArgsT extends any[]> extends Foo<[number, ...SubArgsT]>{ }

Expected behavior: Successful compilation. Array subclasses are not allowed as rest arguments for now, but when it is about generics I expect behavior similar to what is done in #24897

Actual behavior: Failed with TS2574: A rest element type must be an array type.

Activity

  1. AlCalzone commented on Aug 1, 2018

    @AlCalzone
    Contributor

    Interstingly, adding angled brackets works (but requires an array of arrays following the number):

    interface Foo<ArgsT extends any[]> {
    	arr: ArgsT;
    }
    
    interface Bar<SubArgsT extends any[]> extends Foo<[number, ...SubArgsT[]]>{ }
    
    var f: Foo<number[]> = {
    	arr: [1,2,3],
    };
    
    var b1: Bar<string[]> = {
    	arr: [1, [""], ["1", "2"]], // not what OP meant, but it works
    }
    var b2: Bar<string[]> = {
    	arr: [1, "", "1", "2"], // error: [number, string, string] cannot be assigned to [number, ...string[][]]
    }

    And this correctly captures the type OP wants to create

    type Fooify<SubArgsT extends any[]> = 
    	((arg1: number, ...rest: SubArgsT) => any) extends ((...args: infer R) => any)
    	? Foo<R> : never;

    but an interface cannot extend that.

  2. McPrescott commented on Sep 10, 2018

    @McPrescott

    Similarly, it seems that following the last example of AlCalzone that rest element types should be able to be inferred without having to use a functions parameter list like so:

    type dropFirst<T extends any[]> = 
        T extends [any, ...(infer U)] ? U : T;
    // Instead of
    type dropFirst<T extends any[]> = 
        ((...args: T) => any) extends (arg: any, ...rest: infer U) => any ? U : T;

    But the same error occurs: A rest element type must be an array type.

  3. cshaa commented on Oct 16, 2018

    @cshaa

    A minimal example showing the non-symmetricity of function arguments vs. tuple types.

    declare function foo<T0, T extends any[]>(a: T0, ...b: T); // works
    type foo<T0, T extends any[]> = [T0, ...T]; // rest element type must be an array type

    I think this should be supported and it seems as an oversight to me that it isn't in 3.1 already.
    Is there a specific reason for it to be disallowed, or is it just that it wasn't top priority?


    Also, it took me quite a long time to find this issue, so I'm adding a few keywords.
    Keywords: spread a generic tuple in a tuple type, generic tuple rest parameter in a tuple type, spreading array type in type declaration, T extends any[] does not work in tuple literal

  4. paul-marechal commented on Aug 25, 2019

    @paul-marechal

    I would like to extend this issue for code looking like the following:

    function meh<T>(...args: Extract<T, any[]>) {} // works
    type Meh<T> = [...Extract<T, any[]>] // does not work (bug?)

    Hopefully this all boils down to the same actual bug.

  5. ahejlsberg commented on Jun 17, 2020

    @ahejlsberg
    Member

    This is now implemented in #39094.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Fix AvailableA PR has been opened for this issueIn DiscussionNot yet reached consensusSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions