I have a file that looks like the following:
{
"32": 10,
"54": 30,
"58": 30,
"87": 30,
"90": 30,
"99": 30,
"143": 20,
"148": 30,
"151": 10,
"154": 30,
"164": 10
}
I import the file in my program:
import foo from 'myobject.json';
The problem is when I try to access a key from the object with the following syntax:
function doStuff(idx:number) {
let sIdx:string = idx.toString();
let num:number = foo[sIdx]; // ts error here
}
TypeScript complains:
Element implicitly has 'any' type because expression of type 'number' can't be used to index type '{"32":number; ...}'
How do I properly import/type in this case?
CodePudding user response:
When you import data from a JSON file, the type of the value is narrowed to exactly what is in the file. In this case, the type of the JSON data is as if you had written this inline in the file where you're importing the data:
const foo = {
"32": 10,
"54": 30,
"58": 30,
"87": 30,
"90": 30,
"99": 30,
"143": 20,
"148": 30,
"151": 10,
"154": 30,
"164": 10
};
The type of that value is:
{
"32": number;
"54": number;
"58": number;
"87": number;
"90": number;
"99": number;
"143": number;
"148": number;
"151": number;
"154": number;
"164": number;
}
The type has only the eleven keys that you have specified. There is no index signature on the type, so you can't index it using an arbitrary key, which is what the compiler error is telling you. You'll need to check if the value passed to your function is one of the known keys on this type, and decide what to do if the function is passed a value that is not one of the known keys. How you do this really depends on what you are trying to achieve. Here is one possibility:
import foo from './myobject.json';
function doStuff(idx: number) {
const sIdx = idx.toString();
if (isFooKey(sIdx)) {
return foo[sIdx];
} else {
return `${idx} is not in foo!`;
}
}
function isFooKey(key: string): key is keyof typeof foo {
return foo.hasOwnProperty(key);
}
console.log(doStuff(32)); // 10
console.log(doStuff(0)); // 0 is not in foo!
The function isFooKey
is a user-defined type guard that proves to the compiler that the value is actually one of the properties of the object. That is, it will narrow the value "32"
from the type string
to the string literal type "32"
.
An alternative would be to have your doStuff
function only accept a valid key of the JSON data. This would be checked at compile time.
import foo from './myobject.json';
function doStuff(idx: keyof typeof foo) {
return foo[idx];
}
console.log(doStuff("32")); // The compiler allows this.
console.log(doStuff(0)); // The compiler will report: error TS2345: Argument of type '0' is not assignable to parameter of type '"32" | "54" | "58" | "87" | "90" | "99" | "143" | "148" | "151" | "154" | "164"'.
CodePudding user response:
If you just add a signature to your object foo
, things will be fixed
Either do this
const foo:{[x: string]: number} = {
"32": 10,
"54": 30,
"58": 30,
.........
}
or do this
interface Foo {
[x: string]: number,
}
const foo:Foo = {
"32": 10,
"54": 30,
"58": 30,
.........
}
Now you won't get the error, because you have defined the structure of your foo
object that the key will be s string
and value will be a number
CodePudding user response:
Because expression of type 'string' can't be used to index type.
If u use double quotes it is considered as a string!! Remove the double quotes and try.