In typescript
const func = (str: string) => {
const strToNumber = {
account: 0,
goals: 1,
metrics: 2,
};
const number = strToNumber?.[str] || 0;
};
gives the following error:
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ account: number; goals: number; metrics: number; }'. No index signature with a parameter of type 'string' was found on type '{ account: number; goals: number; metrics: number; }'.
I kinda understand why it is giving this error, but at the same time I don't see anything wrong with the code, since I'm using optional chaining and any falsey value will fallback to 0.
What should I do to not get this error? Is there a way that doesn't involve using "as" or "@ts-ignore"?
CodePudding user response:
You can give the strToNumber
object a type like this:
const func = (str: string) => {
const strToNumber : { [key:string]:number } = { // <--
account: 0,
goals: 1,
metrics: 2,
};
const number = strToNumber?.[str] || 0;
};
Here is an example Typescript playground
CodePudding user response:
You probably need to use a guard clause to assert that str
is indeed a key of strToNumber
, so that accessing strToNumber?.[str]
will not throw an error. The guard clause can be something very generic, as such:
function isKeyInShallowObject<T = Record<string, any>>(key: any, obj: T): key is keyof typeof obj {
return Object.keys(obj).includes(key);
}
Then you can use it as such:
const number = isKeyInShallowObject(str, strToNumber) ? strToNumber[str] || 0;
See proof of concept here. An advantage of this is that you no longer need to rely on optional chaining in this case, i.e. strToNumber[str]
will work, since your guard clause will handle the case where str
is not a key of the object.
Alternatively, you can let typescript know that strToNumber
is just a generic dictionary whose key is any string
value:
const func = (str: string) => {
const strToNumber: Record<string, number> = { ... };
// Rest of your code here
};
A dirty but workable hack is a one-liner, where you simply force TypeScript to think that str
is somehow a key of strToNumber
:
const number = strToNumber?.[str as keyof typeof strToNumber] || 0;