What is the correct way in TypeScript to access a Javascript object with [ ] notation and using a variable (that we are initially unsure of its value) that evaluates to a string with the brackets to access an objects property, i.e. myObject[myVariable]
The following code errors as expected as we have an unknown value in x so we can not be sure that it is a key of myDictionary (however, this isn't exactly the error, see code comment):
const myDictionary = {
key1: 'String 1',
key2: 'String 2',
key3: 'String 3',
};
const possibleValuesOfX = [
'key1',
'notAKey1',
'key2',
'notAKey2',
'key3',
'notAKey3',
];
// simulating a random value that could be a possible key of myDictionary
const x =
possibleValuesOfX[Math.floor(Math.random() * possibleValuesOfX.length)];
// The following errors: No index signature with a parameter of type 'string' was found on type '{ key1: string; key2: string; key3: string; }'.ts(7053)
const decode = myDictionary[x];
So I try the following, thinking I'm checking to ensure x is a key of myDictionary before attempting to access myDictionary with x
const myDictionary = {
key1: 'String 1',
key2: 'String 2',
key3: 'String 3',
};
const possibleValuesOfX = [
'key1',
'notAKey1',
'key2',
'notAKey2',
'key3',
'notAKey3',
];
const x =
possibleValuesOfX[Math.floor(Math.random() * possibleValuesOfX.length)];
let decode: string;
if (x in myDictionary) {
// Still produces the same error as above
decode = myDictionary[x];
}
This doesn't stop the error.
Now I can stop the error with const myDictionary: { [key: string]: string } but this also stops autocomplete from working with myDictionary and provides little else from what I can see.
To keep auto complete and stop the error I can do the following:
type myDictionaryKeys = 'key1' | 'key2' | 'key3';
const myDictionary: Record<myDictionaryKeys, string> = {
key1: 'String 1',
key2: 'String 2',
key3: 'String 3',
};
const possibleValuesOfX = [
'key1',
'notAKey1',
'key2',
'notAKey2',
'key3',
'notAKey3',
];
const x =
possibleValuesOfX[Math.floor(Math.random() * possibleValuesOfX.length)];
let decode: string;
if (x in myDictionary) {
decode = myDictionary[x as myDictionaryKeys];
}
But this still feels 'hacky' and overly verbose as I'm casting x as myDictionaryKeys to remove the error and having to type the keys out twice once in myDictionary object and once in myDictionaryKeys type.
Is there a 'proper' way to do this, or a cleaner way?