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

ReadonlyArray with rest parameters #15972

Closed
NN--- opened this issue May 20, 2017 · 18 comments
Closed

ReadonlyArray with rest parameters #15972

NN--- opened this issue May 20, 2017 · 18 comments
Labels
Committed The team has roadmapped this issue Suggestion An idea for TypeScript

Comments

@NN---
Copy link

NN--- commented May 20, 2017

I expect all three functions to be compiled successfully.
TypeScript doesn't allow using ReadonlyArray although it is the same as Array but readonly.

function f(...rest: any[]) { }
function g(...rest: Array<any>) { }
function h(...rest: ReadonlyArray<any>) { }
@mhegazy mhegazy added Suggestion An idea for TypeScript In Discussion Not yet reached consensus labels May 22, 2017
@NN---
Copy link
Author

NN--- commented Sep 19, 2017

This limitation makes harder to use tslint-immutable package.
https://www.npmjs.com/package/tslint-immutable

@adieuadieu
Copy link

Is the following the right place to start with implementing a fix?

https://github.com/Microsoft/TypeScript/blob/14bd0a2d5678d89c474443f02841654c7d014b40/src/compiler/utilities.ts#L930-L940

@mhegazy
Copy link
Contributor

mhegazy commented Feb 6, 2018

There are a few places where we make an assumption about rest params being the globalArrayType, we will need to look at them all and fix them. one place is for example any use of isArrayType with rest params.

@mhegazy
Copy link
Contributor

mhegazy commented Apr 16, 2018

Union and intersections are another example (See #23440).

function dist(x1: number, y1: number, x2: number, y2: number): number
function dist(point1: point, point2: point): number
function dist(...args: number[] | point[]): number {
  // function body
}

@alexander-alvarez
Copy link

I think I'm hitting the same issue when I do something like this:

declare interface R {
    a: [string, number],
    b: [boolean]
}

declare function on<T extends keyof R, K extends R[T]>(val: T, listener: (...args: K) => void): void;
// rest parameter must be array type ^ in ...args


on('b', (a) => {
})

as a workaround I've had to not use the splat args, and overload the method for each arity

@robbiespeed
Copy link

This is also an issue for conditional types inside generic class methods

class Foo <T> {
    bar(...args: T extends number ? number[] : string[]): void { // A rest parameter must be of an array type.
    }
}

@sam-s4s
Copy link

sam-s4s commented Sep 6, 2018

Yeah I've just run into this issue...

remove(...items: (M[] | number[])) {}

The above code should work, but does not :(

@McPrescott
Copy link

McPrescott commented Sep 11, 2018

There is a temporary work around for some of the issues mentioned here, specifically the union types, until problem is resolved

type F1 = (...args: number[] | string[]) => any; // Throws an error
type Fof<T extends any[], R> = (...args: T) => R;
type F2 = Fof<number[] | string[], any>; // Compiles without error

It's not clear to me why this fix works. As you can see in the screenshot below, the type of F2 is (...args: number[] | string[]) => any even though that type is apparently an error.

microsoft typescript issue 15972 - rest parameter error

@NN---
Copy link
Author

NN--- commented Sep 11, 2018

type Fof<T extends any[], R> = (...args: A) => R;
You meant 'T' and not 'A' I guess

type Fof<T extends any[], R> = (...args: T) => R;

@McPrescott
Copy link

Ya

type Fof<T extends any[], R> = (...args: A) => R;
You meant 'T' and not 'A' I guess

type Fof<T extends any[], R> = (...args: T) => R;

Ya I did thanks for pointing that out 👍

@sullvn
Copy link

sullvn commented Sep 14, 2018

I have another (albeit slightly dysfunctional) use case impacted by this. Using Typescript 3.1.0-rc.

class Pipeline<PS extends any[]> {
  // Gives error:
  //
  //     A rest element type must be an array type.
  //
  // NOTE: Technically incorrect because `PS` includes `PS[0]`
  //
  public constructor(fns: [HeadFn<PS[0]>, ...TailFns<PS>]) {
  }
}

interface HeadFn<T> {
  kind: 'head'
  props: T
}

interface TailFn<T> {
  kind: 'tail'
  props: T
}

type TailFns<TS> = {
  [K in keyof TS]: TailFn<TS[K]>
}

Same error with a stronger restriction on the TailFns type parameter:

type TailFns<TS extends any[]> = {
  [K in keyof TS]: TailFn<TS[K]>
}

@forivall
Copy link

forivall commented Nov 1, 2018

Of note, this is also an issue with tuple splat types in typescript > 3.0.

i.e.

// works
function tuple<T extends any[]>(...value: T) {
  return value
}
// compile error
function tuple<T extends ReadonlyArray<any>>(...value: T) {
  return value
}

@ulrichb
Copy link

ulrichb commented Nov 13, 2018

... same for TS 3.0 "Rest elements in tuple types":

type MyTuple1 = [string, ...string[]];

// Error in TS 3.0/3.1:
type MyTuple2 = [string, ...ReadonlyArray<string>];

(I didn't find an own issue for that.)

@megabayt
Copy link

megabayt commented Feb 7, 2019

Subscribing for this

@ericselkpc
Copy link

For those that land here like I did and think they need to use the Fof<> workaround above, in my case it was much easier. I had this:

add: (...items: T[] | Enum<T>[]) => void;

Which I just needed to change to:

add: (...items: (T | Enum<T>)[]) => void;

Might be obvious to all but noobs, but since this was the first hit on Google when I searched on the error message, safe to say I'm not the only noob reading this.

@sam-s4s
Copy link

sam-s4s commented Feb 11, 2019

@ericselkpc It may not matter terribly much, but I'd just like to point out that this solution has one technical problem - it allows mixed arrays... ie. an array that contains items of both type T and type Enum... This may cause problems if you're not careful :)

@robbiespeed
Copy link

@ericselkpc your first example now works in 3.3, my example above also now works.

@ikokostya
Copy link
Contributor

ikokostya commented Feb 14, 2019

Looks like this issue was fixed in #29435

See #29435 (comment)

/cc @ahejlsberg @DanielRosenwasser

@RyanCavanaugh RyanCavanaugh added Committed The team has roadmapped this issue and removed In Discussion Not yet reached consensus labels Feb 25, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Committed The team has roadmapped this issue Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests