Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generic type constraint does not apply to rest parameters #2328

Closed
sccolbert opened this issue Mar 12, 2015 · 8 comments
Closed

Generic type constraint does not apply to rest parameters #2328

sccolbert opened this issue Mar 12, 2015 · 8 comments
Labels
By Design Deprecated - use "Working as Intended" or "Design Limitation" instead

Comments

@sccolbert
Copy link

The following fails to compile even though T is constrained to an array type:

function attach<T extends any[]>(cb: (...args: T) => void): void { }
A rest parameter must be of an array type.
(parameter) args: T extends any[]
@danquirk
Copy link
Member

This is technically by design but it's a reasonable suggestion. We also don't allow subtypes of array without generics.

@danquirk danquirk added the Suggestion An idea for TypeScript label Mar 12, 2015
@RyanCavanaugh RyanCavanaugh added the In Discussion Not yet reached consensus label Mar 17, 2015
@RyanCavanaugh
Copy link
Member

Spec section 3.8.2.2

@RyanCavanaugh RyanCavanaugh added By Design Deprecated - use "Working as Intended" or "Design Limitation" instead and removed In Discussion Not yet reached consensus Suggestion An idea for TypeScript labels May 4, 2015
@RyanCavanaugh
Copy link
Member

This doesn't actually make sense.

The function should be rewritten this way:

function attach<T>(cb: (...args: T[]) => void): void { }

Any production that requires that you write T instead of T[] would require a lie, because the type of the rest arg is always going to be the basic Array type, not some subtype thereof. It would be especially dangerous to flow that type through.

@JoshuaKGoldberg
Copy link
Contributor

@RyanCavanaugh what if the function is meant to be used like the following?

attach((age: number, name: string) => {
    console.log({ age, name });
});

// written explicitly:
attach<[number, string]>(/*... */);

Using the ...args: T[] approach we would then have this typed as (number | string)[] instead of [number, string] right?

@RyanCavanaugh
Copy link
Member

If that's the desired behavior you'd be better off writing some explicit overloads e.g. https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/underscore/underscore.d.ts#L1126

@ds300
Copy link
Contributor

ds300 commented Jun 25, 2017

As a library author this makes me sad, since with overloading you lose the parameter name information. Plus it produces ugly inline documentation.

@YoshiWalsh
Copy link

I'd love to see this decision reconsidered. As I understand it, one of TypeScript's major design goals is to have a type system flexible enough to represent any common JavaScript design pattern. Rest parameters have been supported for years, and generics are a vital part of TypeScript, the fact that you can't use both together is unfortunate.

@theRobinator
Copy link

I'd also like to be able to use this feature. I'm building an abstract command pattern class that I'd like to do something like this for:

abstract class Command<T extends any[]> {
    public load(...args: T);
    public loadIfNeeded(...args: T);
    public clearAndReload(...args: T);
}

Requiring implementing classes to override every method in the abstract class just to provide a type definition is ugly. Implementing this issue's feature would solve this nicely.

@microsoft microsoft locked and limited conversation to collaborators Jul 25, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
By Design Deprecated - use "Working as Intended" or "Design Limitation" instead
Projects
None yet
Development

No branches or pull requests

7 participants