Skip to content

ReadonlyArray with rest parameters #15972

Description

@NN---

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>) { }

Activity

  1. NN--- commented on Sep 19, 2017

    @NN---
    Author

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

  2. adieuadieu commented on Feb 6, 2018

    @adieuadieu
  3. mhegazy commented on Feb 6, 2018

    @mhegazy
    Contributor

    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.

  4. mhegazy commented on Apr 16, 2018

    @mhegazy
    Contributor

    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
    }
  5. alexander-alvarez commented on May 21, 2018

    @alexander-alvarez

    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

  6. robbiespeed commented on Jun 12, 2018

    @robbiespeed

    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.
        }
    }
    
  7. sam-s4s commented on Sep 6, 2018

    @sam-s4s

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

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

    The above code should work, but does not :(

  8. McPrescott commented on Sep 11, 2018

    @McPrescott

    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

  9. NN--- commented on Sep 11, 2018

    @NN---
    Author

    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;
  10. McPrescott commented on Sep 11, 2018

    @McPrescott

    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 👍

  11. sullvn commented on Sep 14, 2018

    @sullvn

    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]>
    }
  12. forivall commented on Nov 1, 2018

    @forivall

    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
    }
    
  13. ulrichb commented on Nov 13, 2018

    @ulrichb

    ... 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.)

  14. megabayt commented on Feb 7, 2019

    @megabayt

    Subscribing for this

  15. ericselkpc commented on Feb 11, 2019

    @ericselkpc

    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.

  16. sam-s4s commented on Feb 11, 2019

    @sam-s4s

    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 :)

  17. robbiespeed commented on Feb 13, 2019

    @robbiespeed

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

  18. ikokostya commented on Feb 14, 2019

    @ikokostya
    Contributor
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

    CommittedThe team has roadmapped this issueSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions