0

... No index signature with a parameter of type 'string' was found on type 'TestObject '.
I want to iterate through an object in typescript using the following code.
For some reason it works in stackblitz but not in my Angular project in vs code...
I know that there is a similar question if not the same question already here where they solve it with a new type or type as any.
Since it works in stackblitz but not in vs code i suspect that there might be a problem with my project setting but I don't know where to look for that.

export class HelloComponent {
  @Input() name: string;
  myTestObject: TestObject = {
    id: 1,
    name: 'Bob',
    age: 40,
    gender: 'male',
  };
  constructor() {
    this.iterateThroughObject();
  }
  iterateThroughObject(): void {
    Object.keys(this.myTestObject).forEach((property) => {
      console.log(this.myTestObject[property]);
    });
  }
}

the type TestObject is in another class

export interface TestObject {
  id: number;
  name: string;
  age: number;
  gender: string;
}

Is this maybe an issue with my tsconfig.json?

/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "noImplicitOverride": true,
    "noPropertyAccessFromIndexSignature": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "sourceMap": true,
    "declaration": false,
    "downlevelIteration": true,
    "experimentalDecorators": true,
    "moduleResolution": "node",
    "importHelpers": true,
    "target": "es2020",
    "module": "es2020",
    "lib": [
      "es2020",
      "dom"
    ]
  },
  "angularCompilerOptions": {
    "enableI18nLegacyMessageIdFormat": false,
    "strictInjectionParameters": true,
    "strictInputAccessModifiers": true,
    "strictTemplates": true
  }
}

Aluan Haddad
  • 29,886
  • 8
  • 72
  • 84

1 Answers1

0

I don't think this is a tsconfig problem. What is happening is that Object.keys(this.myTestObject) returns a string[]. The way you've defined TestObject, it only considers "id" | "name" | "age" | "gender" valid properties to index on, not any generic string.

In other words, Object.keys loses information about the keys of the object it's called on (in this case myTestObject). It defaults to the more generic type string, which in turn cannot be used to index myTestObject.

There are many ways to fix this. The simplest I can think of is to declare a type of type MyTestObjectKey = "id" | "name" | "age" | "gender" and then explicitly cast

(Object.keys(myTestObject) as MyTestObjectKey[]).forEach((key) => ...)

To be slightly safer, you could also explicilty declare

const MyTestObjectKeyArray: MyTestObjectKey[] = ["id", "name", "age", "gender"];
MyTestObjectKeyArray.forEach((key) => ...)

Hope this helps!

Mark Pekala
  • 126
  • 5
  • The latter option would actually be safe. Typescript can't know if properties have been added to an object, so that's why it uses `string[]` instead of the declares keys. However, if you explicitly iterate over the expected keys, it's guaranteed to be safe. See: https://github.com/microsoft/TypeScript/pull/12253#issuecomment-263132208 – siride Jan 15 '23 at 20:28