Jax-p
Jax-p

Reputation: 8531

Access object property using variable in bracket notation in TypeScript

I have object with interface and I would like to dynamically access values by property key.

const tmpUser: IUser = {
    username: "test",
    namespace: "test",
    password: "test"
}

Object.keys(tmpUser).forEach(property=>{
    // Error: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'IUser'.
    console.log(tmpUser[property]);
})

// works
console.log(tmpUser["username"]);

// works
const someKey = "username";
console.log(tmpUser[someKey]);

also tmpUser.hasOwnProperty(property) doesn't help neither.

Upvotes: 0

Views: 3364

Answers (3)

Tony Nguyen
Tony Nguyen

Reputation: 3488

Because Object.keys does not allow use to pass a generic type, its return type is string[], if we want to have type [keyof IUser] we can cast it

const keys: [keyof IUser] = Object.keys(tmpUser) as [keyof IUser]
keys.forEach((property)=>{
    console.log(tmpUser[property]);
})

BUT: It's is unnecessary. If you want to get key and value of that key you can simply use

Object.entries(tmpUser).forEach(([key,value])=>{
   
})

Upvotes: 2

Kousha
Kousha

Reputation: 36219

Throwing another solution here, especially since I'm assuming you'll have some kind of a process function that takes in an object and does something with it:


const process = <O extends { [key: string]: any }>(object: O) => {
    Object
        .keys(object)
        .forEach(prop => {
            // No longer complains
            console.log(object[prop]);
        });
}

process(tmpUser);

Upvotes: 0

Michal
Michal

Reputation: 2073

You can specify that the IUser keys will be of type string (or if you want e. g. string | number):

interface IUser extends Record<string, any> {
    username: string
    namespace: string
    password: string
}

Upvotes: 2

Related Questions