Sean
Sean

Reputation: 667

Typescript iterate over an array of interface fields

I'd like to use an array to iterate through interface properties, however it's throwing a ts compile error on the forEach function:

interface A {
  foo: string
  bar: string
  baz: string
}

function fn(obj: A) {
  ;["foo", "bar"].forEach( (prop: keyof A) => {
    obj[prop] // do stuff
  })
}

The error:

Argument of type '(prop: keyof A) => void' is not assignable to parameter of type '(value: string, index: number, array: string[]) => void'. Types of parameters 'prop' and 'value' are incompatible. Type 'string' is not assignable to type 'keyof A'

Something like this would work, but it feels redundant:

function fn(obj: A) {
  const ar: (keyof A)[] = ["foo", "bar"]
  ar.forEach( (prop: keyof A) => {
    obj[prop] // do stuff
  })
}

Upvotes: 1

Views: 1658

Answers (1)

Brooke Hart
Brooke Hart

Reputation: 4059

TypeScript infers the type of ["foo", "bar"] to be string[], which can't be assigned to type keyof A because it could contain strings that aren't in that type. If you tell TypeScript that your array is of type (keyof A)[] then it works. For example:

interface A {
  foo: string
  bar: string
  baz: string
}

function fn(obj: A) {
  ;(["foo", "bar"] as (keyof A)[]).forEach( (prop) => {
    obj[prop] // do stuff
  })
}

TypeScript playground

That example uses a type assertion, though, which it's preferrable to avoid when possible as it bypasses TypeScript's type checking. You can avoid that by using something like this instead, which will refuse to compile if you attempt to put a string in your array that isn't one of A's property names:

interface A {
  foo: string
  bar: string
  baz: string
}

function fn(obj: A) {
  let values: (keyof A)[] = ['foo', 'bar'];
  values.forEach( (prop) => {
    obj[prop] // do stuff
  })
}

TypeScript playground

Upvotes: 2

Related Questions