TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'User_Economy'

Viewed 2906

I spend most time for that question, but dont have a answer

Error: TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'User_Economy'.   No index signature with a parameter of type 'string' was found on type 'User_Economy'.


    interface User_Economy {
        rep: number
        money: number
        level: number
        xp: number
        box: number[]
    }
    interface User_Interface{
        Economy: User_Economy
    }
    data = await this.client.db.insert_one<User_Interface>('users', User_basic(member.id, message.guild.id));
    const type: keyof {[key: string]: User_Economy} = ['level', 'money', 'rep', 'xp'].find(x => {
                return typed.toLowerCase() === x ? x : null
            })
    data.Economy[type] += Math.floor(parseInt(amount));

How to fix that problem?

1 Answers

The type of the const type that you have defined now is string. As the error suggests, the User_Economy interface has no index signature with a parameter of type 'string', i.e. something like:

interface User_Economy {
  [key: string]: unknown;
}

The const type that you are looking to use in the last line, instead of a keyof {[key: string]: User_Economy} (equivalent to string), should be a keyof User_Economy, i.e. a singular predefined key of User_Economy, in order to reference a key of User_Economy as it is currently defined.

There are other issues with the supplied code, such as the User_Economy.box property not being assignable by the += operator. You would want to use the Exclude utility type to exclude it from the results. Another issue is that the Array.prototype.find() method can return undefined and that must be accounted for before assigning data.Economy[type].

As an example, below is some code that always adds 1 to data.Economy.level, resulting in its value being set to 2:

interface User_Economy {
  rep: number;
  money: number;
  level: number;
  xp: number;
  box: number[];
}
interface User_Interface{
  Economy: User_Economy;
}
type KUEExcludingBox = Exclude<keyof User_Economy, 'box'>;

const data: User_Interface = {
  Economy: {
    rep: 1,
    money: 1,
    level: 1,
    xp: 1,
    box: [],
  },
};

const key: KUEExcludingBox | undefined = (['level', 'money', 'rep', 'xp'] as KUEExcludingBox[])
  .find(x => 'level' === x);
if (key !== undefined) {
  data.Economy[key] += Math.floor(parseInt('1'));
}

console.log(data);

View it on the TypeScript Playground.

Asides
  • You should avoid using keywords like type as variable names.
  • The Array.prototype.find() callback should generally return a boolean value, though it also accepts truthy/falsey values. The first element that the callback returns truthy for will be the element returned by find(). There is no reason in this case for the extra processing of the typed.toLowerCase() === x ? x : null. Just use typed.toLowerCase() === x.
Related