Typescript: .fill() value is optional in JS

Created on 3 Jul 2018  路  4Comments  路  Source: microsoft/TypeScript

I'm really sorry if it's duplication but I couldn't find existing issue.

Code

new Array(3).fill()

Expected behavior:
The JS output for this is just:

[undefined, undefined, undefined]

I know there are more ways to fill dynamic empty array probably better ways but this use case serves many people in order to accomplish something like:

new Array(15).fill().map((v, i) => ({_id: `${i}`}))

Actual behavior:
Throwing the following error: "Expected 1-3 arguments, but got 0"

I will be glad to create a PR to migrate the definition of value property to optional.

Working as Intended

Most helpful comment

For anyone else stumbling across this that happens to have the same problem I was having:

I was trying to create a range function (equivalent to Python, but I didn't need the step argument)

  private range(start: number, end: number) {
    return Array(end - start).fill().map((_, i: number) => i + start)
  }

and was getting this error. In this, case, it was easily remedied by using 0 as a placeholder instead of the implicit undefined:

  private range(start: number, end: number) {
    return Array(end - start).fill(0).map((_, i: number) => i + start)
  }

All 4 comments

This is not defined as optional according to the spec

https://tc39.github.io/ecma262/#sec-array.prototype.fill

22.1.3.6Array.prototype.fill ( value [ , start [ , end ] ] )

It'd also be extremely bad for TS to allow calling fill with no arguments on arrays without undefined in their element type.

I don't really see why you'd want to call fill just to put undefined into the sparse slots in the first place? The only observable difference between new Array(3).fill() is hasOwnProperty, which would be a weird thing to use with an array anyway.

I see your point, actually, the specification said that only start and end are optional but the behavior itself is like I describe, if you pass no variables it just means that value is undefined.

I don't really see why you'd want to call fill just to put undefined into the sparse slots in the first place?

Because I can't iterate over empty array using map/foreach/reduce/etc, see the following example:

new Array(15).map((v, i) => ({_id: `${i}`})) // output: [empty x 15]
new Array(15).fill().map((v, i) => ({_id: `${i}`})) // output: [{_id: '0'}, ...]

Now, again it's maybe not the most right way to create a daynamic array and iterate over it with map but as far as I know it's pretty common.

Nvm, I guess we can close this issue.

For anyone else stumbling across this that happens to have the same problem I was having:

I was trying to create a range function (equivalent to Python, but I didn't need the step argument)

  private range(start: number, end: number) {
    return Array(end - start).fill().map((_, i: number) => i + start)
  }

and was getting this error. In this, case, it was easily remedied by using 0 as a placeholder instead of the implicit undefined:

  private range(start: number, end: number) {
    return Array(end - start).fill(0).map((_, i: number) => i + start)
  }

I still believe value should be made optional to allow looping in a declarative style:

Array(4).fill().forEach(doSomething);

As one would do in Javascript. True, you can overcome this by passing undefined or 0 to fill but it adds useless noise to the code.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Zlatkovsky picture Zlatkovsky  路  3Comments

manekinekko picture manekinekko  路  3Comments

Antony-Jones picture Antony-Jones  路  3Comments

uber5001 picture uber5001  路  3Comments

MartynasZilinskas picture MartynasZilinskas  路  3Comments