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])
})
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])
})