TL;DR
TypeScriptを利用する場合, TypeScriptのバージョンとトランスパイルするtargetのバージョンに気をつけましょう.
古すぎると利用できない構文などがあります.
タイトルのスプレッド構文 [...Array(5)]
に関しては, TypeScript v3.6以上を利用するか, targetにES2015以上を利用すると動くはずです.
反省
2020/02/26
流石に雑な内容の記事のまま放置しすぎたなと思い再確認することにしました.
というか記事全文書き直しました.
元々この記事は,
CodePenの Pen Settings > JS
で JavaScript Preprocessor
を TypeScript
にすると,
スプレッド構文が動かない!?なんで!?
↓
CodePenはトランスパイルのtargetにTSデフォルトの ES3
を指定するなど,
古いJSを出力するような設定になっているのかも (@cfm-art さんのコメントによる)
↓
なるほど!(思考停止)
というあんまりな状態で放置されていました. しかもタイトルにはCodePenと入っていない...
今改めて確認すると, CodePenでTypeScriptを選択した場合でも, スプレッド構文がちゃんと使えるようになっていました.
この1年弱の間に何らかのアップデートがあったものと思われます. つまり今となっては以前の挙動を確認しようがありません. リリースノートが見たい.
具体的に今現在のCodePenでどのような設定が使われているのかはわかっていません. すみません.
検証
さて, 実際に @cfm-art さんの指摘を検証してみます.
検証環境にはTypeScript PlayGroundを利用します.
公式の環境なので, 信頼できると判断します.
現在のTypeScript PlayGroundでは, 左の入力欄にTSのコードを書くと, 右の出力欄にJSにトランスパイルされたコードが出力されます.
便利.
そしてプルダウンからは, TSのバージョンやトランスパイルに利用するtargetのバージョンを選択できます.
便利.
そしてRunを押下すると, 実際に実行することができます.
便利.
現在, TSのバージョン指定には
3.8-Beta
3.7.5
3.6.3
3.5.1
3.3.3
3.1.6
3.0.1
2.8.1
2.7.2
2.4.1
Nightly
が, targetのバージョン指定には,
ES3
ES5
ES2015
ES2016
ES2017
ESNext
がそれぞれ選択できます.
さて.
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Spread_syntax
を見ると, スプレッド構文はECMAScript 2015(ES6)で追加されたようです.
このあたり, バージョンを切り替えて実際に確認してみます.
ソースのTSは以前CodePenで利用したものとおなじ以下のものを利用します.
[...Array(3)].map((_, index) => console.log(`spread operator ${index}`));
v3.7.5 + ES2017
TypeScript PlayGroundアクセス時のデフォルト値です.
Latest stableのようなのでまぁ問題なく動くでしょう.
"use strict";
[...Array(3)].map((_, index) => console.log(`spread operator ${index}`));
spread operator 0
spread operator 1
spread operator 2
動きますね.
v3.7.5 + ES3
targetをES3にします.
"use strict";
var __spreadArrays = (this && this.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
};
__spreadArrays(Array(3)).map(function (_, index) { return console.log("spread operator " + index); });
spread operator 0
spread operator 1
spread operator 2
こいつ...動くぞ...! ばんなそかな.
なんだかポリフィルっぽい印象を受けますね.
v2.4.1 + ES2017
"use strict";
[...Array(3)].map((_, index) => console.log(`spread operator ${index}`));
spread operator 0
spread operator 1
spread operator 2
ほむほむ.
v2.4.1 + ES3
"use strict";
Array(3).slice().map(function (_, index) { return console.log("spread operator " + index); });
sliceになってうまく動かなくなりましたね.
組み合わせ表
ひととおり触ってみたので一覧にします.
動作した組み合わせがoおよびo!で, 動作しなかった組み合わせがxとなります.
oとo!の違いについては後述します.
TS/target | ES3 | ES5 | ES2015 | ES2016 | ES2017 |
---|---|---|---|---|---|
3.7.5 | o! | o! | o | o | o |
3.6.3 | o! | o! | o | o | o |
3.5.1 | x | x | o | o | o |
3.3.3 | x | x | o | o | o |
3.1.6 | x | x | o | o | o |
3.0.1 | x | x | o | o | o |
2.8.1 | x | x | o | o | o |
2.7.2 | x | x | o | o | o |
2.4.1 | x | x | o | o | o |
トランスパイルされたJSは3種類に分けられました.
"use strict";
Array(3).slice().map(function (_, index) { return console.log("spread operator " + index); });
"use strict";
[...Array(3)].map((_, index) => console.log(`spread operator ${index}`));
"use strict";
var __spreadArrays = (this && this.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
};
__spreadArrays(Array(3)).map(function (_, index) { return console.log("spread operator " + index); });
動作しないのは一番上のもので, 下の二つは動作しました.
三番目のものを表内ではo!としています.
表を見るとわかりますが, 基本的にES3とES5ではスプレッド構文はうまくトランスパイルされませんが,
TS v3.6.3以降では動作するようになっています. 興味深いですね.
これはちゃんとTS3.6のリリースノートに記述がありました. 神対応.
In pre-ES2015 targets, the most faithful emit for constructs like can be rewritten as the following array literal However, TypeScript would instead transform the original code into this code: which is slightly different. TypeScript 3.6 introduces a new
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-6.html#more-accurate-array-spread
More Accurate Array Spread
for
/of
loops and array spreads can be a bit heavy. For this reason, TypeScript uses a simpler emit by default that only supports array types, and supports iterating on other types using the --downlevelIteration
flag. The looser default without --downlevelIteration
works fairly well; however, there were some common cases where the transformation of array spreads had observable differences. For example, the following array containing a spread[...Array(5)]
[undefined, undefined, undefined, undefined, undefined]
Array(5).slice();
Array(5)
produces an array with a length of 5, but with no defined property slots.__spreadArrays
helper to accurately model what happens in ECMAScript 2015 in older targets outside of --downlevelIteration
. __spreadArrays
is also available in tslib.
つまり, CodePenで扱うTypeScriptのバージョンがv3.6以上になったため, スプレッド構文が正常に利用できるようになった, と推測できます.
もしくはES2015以降でトランスパイルするようになったかですが.
さいごに
1年かけて, やっと幾分かスッキリできる内容になりました..._(⌒(_´-ω-`)_
ふにゃふにゃなままで記事を放置するのはよろしくないですよね...すみませんでした...
なにか改善点や勘違いしている点, 有力な情報などがありましたら, コメントいただけますと幸いです₍₍(ง˘ω˘)ว⁾⁾
Qiita: JavaScriptで指定したN回分ループする ES2015のspread operatorを使ってループさせたい回数nの配列を作り、map(またはforEach)を使ってループさせる。 CodePenで, 設定からJavaScript Preprocessorを TypeScript Playgroundでも試してみたが, こちらでもspread operatorでのN回ループは動作しなかった. TypeScriptの場合, N回ループしたい場合は なお,
以下, 以前の記事本文
[...Array(5)].map(() => console.log('5回実行'))
// counterが必要な場合
[...Array(5)].map((_, i) => console.log(i))
TypeScript
にすると, spread operatorでのN回ループは動作しなかった.
一方, None
(native JavaScript), Babel
では動作した.
https://codepen.io/akinosora/pen/ywmKZM?editors=1111
https://www.typescriptlang.org/play/Array(N).fill().map(() => doSomething())
のほうが安全かも?create-react-app
の --typescript
オプションでローカル環境に構築したReact+TypeScript環境では,
spread operatorでのN回ループは動作した. なんでや.おかげでローカルで動作するコードがCodePen上で動作せず, 暫く頭を悩ませることとなった.