41

In typescript, How to access object key(property) using variable?

for example:

interface Obj {
    a: Function;
    b: string;
}

let obj: Obj = {
    a: function() { return 'aaa'; },
    b: 'bbbb'
}

for(let key in obj) {
    console.log(obj[key]);
}

but typescript throw below error message:

'TS7017 Element implicitly has an 'any' type because type 'obj' has no index signature'

How to fix it?

8 Answers 8

39

You can also do something like this:

const keyTyped = key as keyof typeof Obj;
const value = Obj[keyTyped];
Sign up to request clarification or add additional context in comments.

1 Comment

It worked out perfectly!
27

To compile this code with --noImplicitAny, you need to have some kind of type-checked version of Object.keys(obj) function, type-checked in a sense that it's known to return only the names of properties defined in obj.

There is no such function built-in in TypeScript AFAIK, but you can provide your own:

interface Obj {
    a: Function;
    b: string;
}

let obj: Obj = {
    a: function() { return 'aaa'; },
    b: 'bbbb'
};


function typedKeys<T>(o: T): (keyof T)[] {
    // type cast should be safe because that's what really Object.keys() does
    return Object.keys(o) as (keyof T)[];
}


// type-checked dynamic property access
typedKeys(obj).forEach(k => console.log(obj[k]));

// verify that it's indeed typechecked
typedKeys(obj).forEach(k => {
    let a: string = obj[k]; //  error TS2322: Type 'string | Function' 
                           // is not assignable to type 'string'.
                          //  Type 'Function' is not assignable to type 'string'.
});

2 Comments

This is awesome complicated. It would be an argument against TS. I would if there is not a simpler solution.
9

I found using keyof to be the easiest solution

const logKey = (key: keyof Obj) => {
    console.log(obj[key])
}

for(let key in obj) {
    logKey(key)
}

Comments

3

I had the same issue and solved it via the following code:

// interface
export interface IDepartment {
  id: string
  name: string
}

let fieldName = 'name' as keyof IDepartment

// access value of provided field-name from object
deptObj[fieldName]

Comments

0

You can use extra function for iteration. TS infers type inside function in a more meaningful way:

interface Obj {
    a: Function;
    b: string;
}

let obj: Obj = {
    a: function () { return 'aaa'; },
    b: 'bbbb'
}

const iterator = <T extends Obj>(obj: T) => {
    for (let key in obj) {
        console.log(obj[key]);
    }
}

Playground

Comments

0

Use

Object.entries(obj).forEach((value, key) => {
    console.log(value);
})

Or

Object.entries(obj).map(([key, value]) => {
    return `${key} - ${value}`
})

Comments

0

Using Object.keys() + forEach() instead of for...in:

Object.values(obj).forEach((value) => {
  console.log(value);
});

This way, TypeScript will be able to infer types properly, without having to do any extra type casting/infer.

Comments

-2

I tried your code above as a quick test in WebStorm, and it compiled and ran without error. If you are using a version of Typescript before 2.0, I suggest trying Typescript 2.0 or higher.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.