Skip to content

Rest elements in generic tuple #26113

@vmit

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

AlCalzone

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.

McPrescott

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.

cshaa

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

paul-marechal

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.

ghost

ghost commented on Jan 24, 2020

@ghost

This still seems to be an issue. I have the simple case:

type Combine<T, U> = U extends unknown[] ? [T, ...U] : never;

Which fails currently because it can't determine that U is valid as a rest parameter.

4 remaining items

Loading
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

      Participants

      @cshaa@ahejlsberg@mhegazy@vmit@paul-marechal

      Issue actions

        Rest elements in generic tuple · Issue #26113 · microsoft/TypeScript