In a React component I have something similar to:
if (props.someArray){ // typecheck because someArray is of type 'things[] | undefined'
props.someArray.forEach((element, i) => {
someFunction(i, element, props.someArray); // error despite typecheck (due to "| undefined")
});
}
// The functions someArray argument's type is only 'things[]', not 'things[] | undefined'
const someFunction = (i: number, element: thing, someArray: things[]) => {
someArray[i] = // do some stuff;
}
Since the typecheck is already done before the loop, is it really necessary to do it again before calling the function inside the loop? (inconveniently checking on every iteration instead of just once before looping).
if (props.someArray){ // <- I'd like to keep just this
props.someArray.forEach((element) => {
if (props.someArray) { // <- is this really necessary?
someFunction(element, props.someArray);
}
});
}
CodePudding user response:
Array.prototype.forEachuses a closure (i.e. an entirely separatefunction) for the loop body, and TypeScript is cautious about how type-information passes between function boundaries.- Namely because TypeScript has no way of knowing how
forEachwill invoke the callback because any script can simply overwrite or replace the defaultArray.prototype.forEachimplementation and do something silly, like repeatedly invoke the function on only the first element or something.
- Namely because TypeScript has no way of knowing how
If you use
for(of)instead then you won't have any problems because it doesn't use a closure: as it's a native language construct the TypeScript type engine (is that a word?) can reason about it more than it can with.forEach.Other reasons to use
for(of)instead offorEach:- You can use
awaitinsidefor(of). - You can use
breakto abort a loop (you can't abort aforEachwithout usingthrow). - It works with any iterable, whereas
forEachis only available on certain specific collection types (Array,NodeList, and a few others).
- You can use
So change your code to this:
if ( props.someArray ) {
for( const el of props.someArray ) {
someFunction( el, props.someArray );
}
}
If you want to get both the array-element and its index inside the for loop then use entries() like so:
if ( props.someArray ) {
for( const [idx, el] of props.someArray.entries() ) {
someFunction( idx, el, props.someArray );
}
}
