0

I have the following object.

type Test = {
  0: number[];
  1: number[];
};

There will always be 2 keys named '0' and '1' in the object.

I want to iterate each key in the object and print the number in the value.

const logEveryItem = (test: Test): void => {
  for (let key in test) {
    test[key].forEach((i: number) => console.log(i));
  }
};

But test[key] from the 3rd line, TypeScript gives the following error.

TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Test'. No index signature with a parameter of type 'string' was found on type 'Test'.

How should I fix this issue?

3 Answers 3

3

Why there is an error ?

Because for .. in operator, by the default, uses string type for iterable property.

const logEveryItem = (test: Test): void => {
    // let prop: string
    for (let prop in test) {

    }
};

string type is to wide for test keys. For instance, you are not allowed to use test['any string'] to access a property. IN this case prop should be 0 | 1. TypeScript does not infer it as 0 | 1 be the default because how in operator works. See this example:

type Test = {
    0: number[];
    1: number[];
};

class SuperTest {
    foo = 'hello'
}

class SubTest extends SuperTest {
    0: number[] = [1, 2, 3]
    1: number[] = [4, 5, 6]
}

const logEveryItem = (test: Test): void => {
    // let prop: string
    for (let prop in test) {
        console.log(prop)
        test[prop].forEach() // run time error
    }
};

logEveryItem(new SubTest())

Somebody could expect that it will log "0" and "1", but it will also log "foo". Please see for .. in docs.

... including inherited enumerable properties.

So, now we know that it is not safe to assume that we will only iterate through 0 | 1. This is why prop infers as a string.

If you are interested in object values, I think it worth using Object.values:


const logEveryItem2 = (test: Test): void => {
    Object.values(test)
        .forEach(elem => {
            console.log(elem)
        })
};
Sign up to request clarification or add additional context in comments.

Comments

1

You either want a record:

type Test = Record<string, number[]> // or Record<number, number[]> if you want your key to be a number. 

which is the same as :

type Test = {
  [key: string]: number[]
};

or a tuple

type Test = [number[], number[]] // could be of the length you want. 

2 Comments

Tuple / Record depends on how he wants to call logEveryItem. Tuple: logEveryItem([[0,1],[2,3]]) Record: logEveryItem({"0":[0,1],"1": [2,3]});
In his example, the key is a number.
-1

The type should be:

type Test = {
  [key: string]: number[]
};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.