Home > database >  typing an import object with typescript
typing an import object with typescript

Time:12-25

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.

  • Related