I think the bigger issue is that Array.prototype.forEach has the type
forEach(callbackfn: (value: T, index: number, array: $ReadOnlyArray<T>) => any, thisArg?: any): void;
https://github.com/facebook/flow/blob/3baafb0f2191353cd896d6fe087aea535bc8606e/lib/core.js#L211.
You can see that the value parameter has type T, which is determined by the type of the elements in the array. In your case, Flow is (most likely) assuming the type of the array ['name', 'age'] to be string[]. Thus, the type T is set to string.
Now, when you try to access person[key], Flow will complain that you are missing an indexer property. This is accurate since you are trying to use a generic string access on the Person instance. This problem persists even after removing the conditional, which hints that Flow is unable to refine the string type to be one of 'name' and 'age'.
It would be nice if Flow could refine something like this
/* @flow */
class Person {
name: string;
age: number;
}
const person: Person = new Person();
person.name = 'Bob';
person.age = 25;
['name', 'age'].forEach(key => {
if (key === 'name') {
console.log(person[key]);
}
});
not necessarily because it's useful but because it is so explicit and should be a safe access at that point.
I would try to avoid using a loop through a list of properties to get/set properties on an object since Flow doesn't deal with the nuances of arrays that act like tuples yet. Plus, it's more future-proof to loop through the object itself (e.g., Object.keys) in case the object's properties ever get changed.