0

The following code:

interface Foo {
  bar: string;
  qux: string;
  baz: number;
}

const foo: Foo = {
  bar: '42',
  qux: 'baz',
  baz: 5
};

const keysToIterateOver = [ 'bar', 'qux' ];

keysToIterateOver.forEach(key => foo[key] = 'newStringValue');

gives TypeScript compile error:

Element implicitly has an 'any' type because type 'Foo' has no index signature

How can I tell the compiler that I am only iterating over keys that have a string value and can safely reassign their values?

Esa Toivola
  • 1,538
  • 3
  • 16
  • 27
  • 1
    Note that the rule is not prohibiting the use of any. It's prohibiting the use of **implicit** any. Just make it **explicit** that the type is any, and the error disappears: `(foo as any)[key] = 'newStringValue'` – JB Nizet Dec 25 '17 at 07:50

2 Answers2

2

You can achieve this by specifying the type of keysToIterateOver:

const keysToIterateOver: (keyof Foo)[] = [ 'bar', 'qux' ];

Otherwise the inferred type is string[], hence the error

Aleksey L.
  • 35,047
  • 10
  • 74
  • 84
  • OK, this suppresses the error. But when I do: const keysToIterateOver: (keyof Foo)[] = [ 'bar', 'qux', 'baz' ] the compiler doesn't give any error even though I'm now essentially trying to assign a string value to foo.baz – Esa Toivola Dec 25 '17 at 08:00
  • Sorry, missed the _have a string value_ part – Aleksey L. Dec 25 '17 at 08:55
  • Well, essentially I just want to tell the compiler that I know what I'm doing and your answer solves that. I'm just surprised that the compiler doesn't warn if I iterate over wrong keys. – Esa Toivola Dec 25 '17 at 11:04
  • 1
    `string|number` is inferred, that's why string is allowed. If you'll try to do something like `foo[key] = false` - it will result in error – Aleksey L. Dec 25 '17 at 11:35
0

Compiler can not detect dynamic property's type and considers the property to have any type. As a workaround you can write your interface with indexer. This will tell to the compiler that any dynamic accessed property with [] indexer contains string or number and the foo[key] = 'newStringValue' assignment is correct.

interface Foo {
    [prop: string]: string | number,
    bar: string;
    qux: string;
    baz: number;
}

Another variant is to remove the "noImplicitAny": true, from tsconfig.json file, but it is not the best one.

Suren Srapyan
  • 66,568
  • 14
  • 114
  • 112