You will find this GitHub thread an interesting read. The issue is related to the inability to infer a common type between a union of arrays (in your case number[] and string[]). Since v3.3enter link description here, though, forEach can be called on a union of arrays, unless the --noImplicitAny flag is on (as the first arg of the callback will implicitly be typed as any).
So nowadays your issue can be solved without as casts, but still requires an explicit type annotation inside the callback:
type union = number[] | string[];
const i : union = [];
i.forEach((elem: number | string) => {
//ok, do something
});
This is more faithful to your State type, as explicit casts are not safe. Having a union of arrays usually indicates that a generic would be more appropriate. Here is how you would change the interface to preserve the type-checking and avoid the initial problem altogether:
export interface State<I extends number | string>{
ids: I[];
}
const state: State<string> = {ids: [1,2,3]}; //error
state.ids.forEach(s => { }); //ok if above is fixed
Also, see this Q&A about the same problem applied to map method.
(<string[]>state.ids).forEach(s => { });would work as a one-liner(state.ids as string[]).forEach(s => { });should also work