3

I am using for... in loop to iterate over an object using square brackets notation, TypeScript complains saying the following:

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'EVENT'. No index signature with a parameter of type 'string' was found on type 'EVENT'.ts(7053)

I Know if this wasn't a loop I could tell TypeScript that "a" can be only certain values, but by using a loop I can't give types so I don't know what to do The problem is I think I can't tell Typescript that in event[a] "a" can take a few values only

interface EVENT {
    imageURL: string;
    artist: string;
    location: string;
    city: string;
    seat: number;
    direction: string;
    country: string;
    type: string;
    date: string;
    tickets_available: number;
    tickets_left: number;
    id: string;
    description: string;
    price: number;
  }
data.filter((event: EVENT) => {
        // a = key of the object data
        for (let a in event) {
          let aSplit =
            typeof event[a] === "string"
              ? event[a].split(" ").map((element: string) => element.toLowerCase())
              : event[a];
          // b = word of searchTerm string
          for (let b of querySplit) {
            if (
              a === "artist" ||
              a === "location" ||
              a === "city" ||
              a === "country" ||
              a === "type"
            ) {
              if (aSplit.includes(b.toLowerCase())) matches.push(event);
            }
          }
        }
      });

I am using the latest typescript with the latest nextJS framework, tsconfig set to aim for ES2015 ScreenShot of the code

1
  • You can use Object.keys with an assertion as (keyof EVENT)[] as an alternative Commented Apr 6, 2022 at 21:02

3 Answers 3

18

I usually use the following pattern:

interface Foo {
    str: string,
    num: number,
}

const foo: Foo = {
    str: "one",
    num: 1,
};

let i: keyof Foo;
for (i in foo) {
    console.log(foo[i]);
}



Playground Link

Sign up to request clarification or add additional context in comments.

Comments

4

As the TypeScript error says, "The left-hand side of a 'for...in' statement cannot use a type annotation."

However, you can create a typed variable within the for...in loop that does have a type, and use that to index your object.

Here's a modified version of the snippet in your question. I've added an empty data variable and removed the querySplit code because those parts don't have the necessary context in your snippet to resolve TypeScript errors.

You'll also note I had to replace your event[a] code with a variable, because accessing the value using square bracket notation repeatedly doesn't work properly with TypeScript's type narrowing.

interface EVENT {
    imageURL: string;
    artist: string;
    location: string;
    city: string;
    seat: number;
    direction: string;
    country: string;
    type: string;
    date: string;
    tickets_available: number;
    tickets_left: number;
    id: string;
    description: string;
    price: number;
}

// Just creating an empty array so TypeScript doesn't complain about `data`
let data: EVENT[] = [];

data.filter((event: EVENT) => {
    // a = key of the object data
    for (let a in event) {
        // Create new typed variable for this iterations' value of `a`
        const key = a as keyof EVENT;
        // Look up `event[key]` once so TypeScript can narrow its type
        const value = event[key];

        let aSplit = typeof value === "string"
        ? value.split(" ").map((element: string) => element.toLowerCase())
        : value;

        // More stuff here
    }
});

TypeScript Playground

Comments

3

I don't want to be forced to use let instead of const, so I did this and it worked, it's a little more verbose, but I'm ok with it:

interface Foo {
    str: string,
    num: number,
}

const foo: Foo = {
    str: "one",
    num: 1,
};


for (const i in foo) {
    console.log(foo[i as keyof Foo]);
}

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.