1

I'm creating a frontend-app with ts/react/redux. Im familiar with typed languages, but, it seems, not enough.

Situation: There is react component (we dont care about JSX here):

import React from 'react';
import './MathComponent.css';

interface MathData {
    mathExpectation: number,
    variance: number,
    standardDeviation: number,
}

interface Props {
  data: MathData,
}

export const MathComponent: React.FC<Props> = ({
   data,
}) => {

 const mathConvert = (num: number) => {
 // some logic here
    return number+1;
 }
 
 const myData = {...data};
 
 const newData = Object.keys(data).map((key:string)=>{
    myData[key] = mathConvert(myData[key]); 
 });
 
  return (
  ...JSX
  )
}

And here I have, as far as I understand, a common issue: myData[key] underline as an error with text:

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

I saw some similar questions, but didnt understand explaining.

So the idea is to iterate over all properties and mutate "myData" object using mathConvert-fnc on every property. I know, that mutate object is usually a bad approach, but I cant see here any other options.

I think, the main question: how to fix a type error, secondary: mabye there is a better approach to enumerate obj props and use my fnc on it?

Alexandr Mrgt
  • 13
  • 1
  • 4
  • 1
    Does this answer your question? [Object.keys iteration causing Typescript error "Element implicitly has an 'any' type because index expression is not of type 'number'"](https://stackoverflow.com/questions/65383113/object-keys-iteration-causing-typescript-error-element-implicitly-has-an-any) – jonrsharpe Aug 11 '21 at 15:56

2 Answers2

0

Typescript can be a pain in the ass when it comes to things like these. I think you can avoid getting this error in one of the following ways:

  • remove the : string from the map() function
  • adjust your typescript.config.json to have the property "noImplicitAny": false. This will ignore all implicit anys though, so that might not be what you want.
  • put a // @ts-ignore comment above the affected lines. This will ignore other TS warnings on that line too, of course, so use at your own risk :)
  • cast that motherfudger: myData[key as any]

As for the second question, you can use for (var key in obj) {.. although I wouldn't say that's necessarily better. Just different.

Additionally, your code has a missing variable name:

const  = Object.keys(data).******
paddotk
  • 1,359
  • 17
  • 31
  • 1 - didnt help, 2 - yes, its rough approach, 3 - same, 4 - didnt understand where and how to cast, can u clarificate it? – Alexandr Mrgt Aug 11 '21 at 16:14
  • If you cast something as a type, it tells TS 'just assume this value/object/whatever is of the specified type'. If you do this `(myData[key] as string) = mathConvert(myData[key] as string);` (not fully sure if that'll work, but you could try) TS assumes `myData[key]` is a string and should be content with it. Or, if that doesn't satisfy TS, cast as `any` instead of `string` to make it know the type doesn't matter. – paddotk Aug 11 '21 at 16:17
  • Apologies, the `key` itself is the issue I guess, not the value of that property. In that case it's `myData[key as any]` – paddotk Aug 11 '21 at 16:20
  • Unlucky, it didnt work. Same error message with -> myData[key as any] : Element implicitly has an 'any' type because expression of type 'any' can't be used to index type '{ mathExpectation: number; variance: number; standardDeviation: number; }'. – Alexandr Mrgt Aug 11 '21 at 16:30
  • One more thing you could try is to cast `myData` as `any` to make TS not know it's an object. Otherwise, I don't know. We configured `"noImplicitAny": false` in our app for this very reason, very annoying ;) – paddotk Aug 11 '21 at 16:37
0

This is not a react but a typescript question.

Object.keys(data) returns an array of strings. myData is of type MathData because of how it was initialized.

To fix the error you should tell typescript that the key to use is one of the keys of your object, and not just any string, by casting it so:

myData[key as keyof MathData] = ...

I know, that mutate object is usually a bad approach, but I cant see here any other options.

If you want to do things functionally, instead of mutating myData you could use a reducer that returns an object with the same keys as your initial object, with your mathConvert function applied to the values of the new object returned. You set an empty object as the initial value, the new object to be returned as the accumulator, and what you reduce are the objects keys. Something like that:


type MathDataKey = keyof MathData;
const newData = Object.keys(data).reduce((acc: Partial<MathData>, key)=>{
    acc[key as MathDataKey] = mathConvert(myData[key as MathDataKey]); 
    return acc;
}, {});

Or you could use a library like lodash that lets you map over objects values.

Denis H.
  • 61
  • 1
  • 5