I have a JSON object imported from a JSON file (with resolveJsonModule: true
). The object looks like this:
"myobject": {
"prop1": "foo",
"prop2": "bar"
}
and it's type therefore looks like this:
myobject: { prop1: string, prop2: string }
That's very nice but when I try to use a for...in
loop,
for (const key in myobject) {
console.log(myobject[key])
}
I get this error:
TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ "prop1": string; "prop2": string; }'.
No index signature with a parameter of type 'string' was found on type '{ "prop1": string; "prop2": string; }'.
I understand that this means the iterator key
is of type string
and not of type 'prop1' | 'prop2'
'prop1' | 'prop2'
. But I don't understand why the iterator doesn't get this type because I'm explicitly iterating through the property names of myobject
. Did I miss a tsconfig property that enables this behavior? I would like not to do this:
for (const key in myobject) {
console.log(myobject[key as 'prop1' | 'prop2'])
}
Because:
A better way to this is:
for (const key in myobject) {
console.log(myobject[key as keyof typeof myobject])
}
In this way, it won't break when you add a property or rename it
Three solutions for typing for...in
loops, I am aware of:
A type assertion will force key
type to be narrowed to myobject
keys:
for (const key in myobject) {
console.log(myobject[key as keyof typeof myobject])
}
The key variable cannot be typed inside the for-in loop, instead we can declare it outside:
let key: keyof typeof myobject // add this declaration
for (key in myobject) {
console.log(myobject[key]) // works
}
function foo<T>(t: T) {
for (const k in t) {
console.log(t[k]) // works
}
}
foo(myobject)
key
in a for...in
loop will by design default to type string
. This is due to the structural type system of TypeScript: the exact properties' keys shape is only known at run-time, the compiler cannot statically analyze, what properties are present on the object at compile-time. A key
type narrowed to myobject
properties would make the for...in
loop an unsafe operation type-wise.
Note: Some linked resources discuss Object.keys
, for which the same argumentation holds.
Why doesn't Object.keys
return a keyof type in TypeScript? - by Ryan Cavanaugh
Comment by Anders Hejlsberg in TypeScript#12253 - also mentions for...in
TypeScript#32321 links to a multitude of duplicate issues
Specific comment towards for...in
by Anders Hejlsberg:
I have my doubts about this one. In
for (var k in x)
wherex
is of some typeT
, it is only safe to say thatk
is of typekeyof T
when the exact type ofx
isT
. If the actual type ofx
is a subtype ofT
, as is permitted by our assignment compatibility rules, you will see values ink
that are not of typekeyof T
.
if you want to have an object to be dynamic in the future create a model like this
interface PropertyItemModel {
propName: string;
propValue: string;
}
and in the component you can fetch data by loop
export class AppComponent {
items: PropertyItemModel[] = [];
constructor() {
this.items = [
{ propName: "1", propValue: "foo" },
{ propName: "2", propValue: "bar" }]
this.items.forEach(item => {
console.log(`name: ${item.propName} - value: ${item.propValue}`)
});
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.