I have a dead simple component. Works perfectly in javascript.
const Test = (props: any) => <div>{props.children}</div>;
const Root: React.SFC<{}> = props => {
return (
<div className="Root">
<h1>hello world.</h1>
<Test>{[...Array(20)].map((_, index) => <h1>test{index}</h1>)}</Test>
</div>
);
};
export default Root;
But doesn't work in typescript. Why?
Both use same React version.
EDIT:
TypeScript: https://codepen.io/anon/pen/eKGoWo
JavaScript: https://codepen.io/anon/pen/GGMLOv
It works if you change it from that spread array map to
<Test>{Array.from({length:20}, (_, index) => <h1 key={index}>test{index}</h1>)}</Test>
(I also added key
to that, since React complains once it starts working. :-) )
Not working: https://codepen.io/anon/pen/XYeQzv?editors=1010
Working: https://codepen.io/anon/pen/eKGoya?editors=1010
It has to do with how TypeScript transpiles that spread notation. TypeScript is converting that [...Array(20)].map(/*...*/)
to this:
Array(5).slice().map(/*...*/)
The problem with that is that Array(20)
creates an array of length 20 with no entries in it. slice
replicates that. map
only visits entries that actually exist in the array, not gaps. But [...Array(20)]
creates an array with 20 entries containing undefined
, which map
will visit:
const a1 = [...Array(5)];
console.log(0 in a1); // true
const a1m = a1.map((_, index) => index);
console.log(0 in a1m); // true
console.log(a1m); // 0, 1, 2, 3, 4
const a2 = Array(5).slice();
console.log(0 in a2); // false
const a2m = a2.map((_, index) => index);
console.log(0 in a2m); // false
console.log(a2m); // (gaps)
Look in the real console (the snippet console gives the impression values exist in the array when they don't).
Yury Tarabanko kindly found a bug report for it.