Home > Software engineering >  TypeScript type in a for... in loop on an object
TypeScript type in a for... in loop on an object

Time:04-07

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

CodePudding user response:

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

CodePudding user response:

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

  • Related