はじめに
連続した値の配列を作りたいことって結構ありませんか?C#のEnumerable.Range(0, 100)
、Pythonのrange(0, 100)
や、Haskellの[0..99]
に相当する機能です。僕は結構あります。
JavaScriptには相当する組み込み機能がなく、さらにググって出てくるコードぺとっと貼ってTypeScriptコードとしてトランスパイルするとts-lintが警告しまくってきたので、こうしたらいいという書き方を備忘しておきます。
[...new Array(100).keys()]
との出会い
ぐぐると、まずこれに出会うと思います。リーズナブルなコードですね。
[...new Array(100).keys()];
-
undefined
を100個含む配列を生成して、(new Array(100)
) - 各要素のインデックスを取り出して、(
keys()
) - オブジェクトをその場で展開して、(
...
)
配列にする、って感じですね。
参考
- https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array#%E6%A7%8B%E6%96%87
- https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/keys
- https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Spread_syntax
Replace Array constructor with an array literal
とかいうエラー
ts-lintのprefer-array-literalがtrue
になっているせいです。筆者の場合は、tslint-microsoft-contrib
由来でtrue
になっていました。
もちろん、このプロパティをfalse
にしてもいいのですが、それをやりはじめるとキリがないですし、解決法も極めてシンプルでnew
を取り除くだけです。
// [...new Array(100).keys()];
[...Array(100).keys()]; //newを取り除きました
newをとると何が起きるか
上記で問題ないので、余談ですが「いやいや、これnewをとるとコンストラクタが呼び出されるんじゃなくて関数呼び出しになっちゃうよね?その場合どうなるの?」と思いませんか?
ググってみたけど、なぜかイマイチ日本語情報が見つからない…と困っていたのですが、結局ECMA2018の標準に書いてありました。困ったときは規格チェックが一番ですね。
also creates and initializes a new Array object when called as a function rather than as a constructor. Thus the function call Array(…) is equivalent to the object creation expression new Array(…) with the same arguments.
http://www.ecma-international.org/ecma-262/9.0/index.html#sec-array-constructor
ということですので、new Array(...)
と同じだよとのことです。
Type 'IterableIteratorShim<number>' must have a '[Symbol.iterator]()' method that returns an iterator.
とかいうエラー
tsconfig.jsonでのtargetによってはこのエラーが出ることがあります。
これは、keys()
ではなくmapの第二引数でインデックスを取ることで解決できます。
// [...new Array(100).keys()];
// [...Array(100).keys()];
[...Array(100)].map((_, i) => (i)); //第二引数はインデックス
結論
↓こういうのつくっておくとよい。
const range = (begin: number, end: number) => ([...Array(to - from)].map((_, i) => (from + i)));