Home > front end >  TypeScript- assert type of keys in Object.entries forEach
TypeScript- assert type of keys in Object.entries forEach

Time:04-02

While using Object.entries() it returns correct values types, but keys are as string[] which is not correct. I want to force TS to be aware of my keys. I tried to use as const on object but this did nothing.

Is it possible to assert type in this case?

const demo = {
  a: 'TEST',
  b: 222,
} as const

Object.entries(demo)
  .forEach(([key, value]) => { // key is string and not "a" | "b"
    console.log([key, value])
  })

// reproduce same types as above
Object.entries(demo)
  .forEach(([key, value]: [string, typeof demo[keyof typeof demo]]) => {
    console.log([key, value])
  })

// now trying to change string to actual keys, error :(
Object.entries(demo)
  .forEach(([key, value]: [keyof typeof demo, typeof demo[keyof typeof demo]]) => {
    console.log([key, value])
  })

// so instead trying to force somehow type assertion
Object.entries(demo)
  .forEach(([key as keyof typeof demo, value]) => { // how to make assertion???
    console.log([key, value])
  })

Playground

CodePudding user response:

keys are as string[] which is not correct

It was designed to be that way, because objects can be extended. You may know that it wasn't extended, but the type system can't enforce that. An example:

interface Person {
  name: string;
  age: number;
}

interface Employee extends Person {
  department: string;
}

const someFunction (person: Person) {
  Object.entries([key, value] => {
    // `key` will sometimes be 'name' or 'age', but those aren't its only
    // values. In this example, it will be 'department', and it could be
    // absolutely any string, hence the type string.
  });
}

const alice: Person = { name: 'alice', age: 30 }
const bob: Employee = { name: 'bob', age: 30, department: 'legal' }

someFunction(alice); // legal of course
someFunction(bob); // Also legal

If you'd like to assert that you know there are no extra properties, the following is probably the easiest way:

Object.entries(demo)
  .forEach(([k, value]) => {
    const key = k as keyof typeof demo
    console.log([key, value])
  })
  • Related