I'm not sure what I am missing in the code below to stop getting the error that says that the forEach
method doesn't exist.
type Foo = Array<string> | string;
type FooCollection = { [key: string]: Foo }
const bar = (data: FooCollection) => {
Object.keys(data)
.forEach((key) => {
if (Array.isArray(data[key])) {
// this forEach is disputed
data[key].forEach((v, i) => {
console.log(v, i);
});
}
});
};
And this code returns no error:
const baz = (value: Foo) => {
if (Array.isArray(value)) {
value.forEach((v, i) => {
console.log(v, i);
});
}
};
So I found out that this would work but was not sure how good this solution is?
const qux = (data: FooCollection) => {
Object.keys(data)
.forEach((key) => {
if (Array.isArray(data[key])) {
baz(data[key]);
} else {
// ...
}
});
};
CodePudding user response:
TypeScript does not narrow down properties of variables - it only narrows variables themselves (unions). Doing
if (Array.isArray(data[key])) {
tests a property of a variable, but not a variable itself, which is why the above fails and, as you saw, if (Array.isArray(value)) {
succeeds.
While you could fix it by putting the value at the key into a standalone variable first:
const bar = (data: FooCollection) => {
Object.keys(data)
.forEach((key) => {
const value = data[key];
if (Array.isArray(value)) {
// do stuff with value
A better approach would be to skip the key altogether, because it looks like you only care about the values.
const bar = (data: FooCollection) => {
Object.values(data)
.forEach((value) => {
if (Array.isArray(value)) {
// do stuff with value
If you do need to do stuff with the key as well as the value, use Object.entries
to get both at once.
const bar = (data: FooCollection) => {
Object.entries(data)
.forEach(([key, value]) => {
if (Array.isArray(value)) {
// do stuff with key and value