0

I have the following function:

const [dataLoc, setDataLoc] = useState({date: "No data received yet from sensor", coords: {}});

I set the location here:

Geolocation.getCurrentPosition(
      location => {
        const date = dateToString(location.timestamp);
        const coords = location.coords
        setDataLoc({date, coords})
      }
)

With coords interface:

export interface GeoCoordinates {
    latitude: number;
    longitude: number;
    accuracy: number;
    altitude: number | null;
    heading: number | null;
    speed: number | null;
    altitudeAccuracy?: number | null;
}

From:

import Geolocation from 'react-native-geolocation-service';

I want to render the data like this:

<Text style={styles.data}>{dataLoc.coords.latitude}</Text>

But I receive:

error: SyntaxError: .../App.tsx: Unexpected token

I can't receive any properties of the object because the object is empty {} like I stated in useState().

When I try to define the object in useState() I get an error because e.g. altitude can be a number or null.

My question is how can I add coords to dataLoc without defining it and still retrieving the object elements or defining it that some values can be a number or null?

I also tried to define it in useState() as:

const [dataLoc, setDataLoc] = useState({
date: "No data received yet from sensor", 
coords: { 
  latitude: 0,
  longitude: 0,
  altitude: 0,
  accuracy: 0,
  altitudeAccuracy: 0,
  heading: 0,
  speed: 0
}
});

But then I receive:

Type '{ latitude: number; longitude: number; altitude: number 
| null; accuracy: number; altitudeAccuracy: number | null; 
heading: number | null; speed: number | null; }' is not 
assignable to type '{ latitude: number; longitude: number; 
altitude: number; accuracy: number; altitudeAccuracy: number; 
heading: number; speed: number; }'.
Types of property 'altitude' are incompatible.
Type 'number | null' is not assignable to type 'number'.
Type 'null' is not assignable to type 'number'.
Tim4497
  • 340
  • 3
  • 19

2 Answers2

1

You need to be explicit about the type of your state value because it can't be inferred from the init value.

For example if your state value is a number type annotation is not required.

const [value, setValue] = useState(0); // TypeScript infers the number type

setValue(53); // Ok
setValue('some string'); // Error

But let't say your value can be either a number or a string. It's impossible for TS to infer that from the init value because a value can't be simultaneously a string and a number. So we we pass the type to this generic useState function.

const [num, setNum] = useState(0); // TypeScript infers the number type
const [value, setValue] = useState<string | number>(0); // We explicitly pass string | number

setNum('some string'); // Error
setValue('some string'); // Ok

Now going back to your specific example, when you initialize your state like this.

const [dataLoc, setDataLoc] = useState({
  date: "No data received yet from sensor", 
  coords: { 
    latitude: 0,
    longitude: 0,
    altitude: 0,
    accuracy: 0,
    altitudeAccuracy: 0,
    heading: 0,
    speed: 0
  }
});

as shown in the error, this is the type that TS infers from that

{
  date: string;
  coords: { 
    latitude: number;
    longitude: number;
    altitude: number;
    accuracy: number;
    altitudeAccuracy: number;
    heading: number;
    speed: number;
  };
}

but that doesn't represent the reality, so you'd need to define the type or get it from the library and pass it to useState.

interface DataLoc {
  date: string,
  coords: { 
    latitude: number;
    longitude: number;
    accuracy: number;
    altitude: number | null;
    heading: number | null;
    speed: number | null;
    altitudeAccuracy?: number | null;
  };
}

const [dataLoc, setDataLoc] = useState<DataLoc>({
  date: "No data received yet from sensor", 
  coords: { 
    latitude: 0,
    longitude: 0,
    altitude: 0,
    accuracy: 0,
    altitudeAccuracy: 0,
    heading: 0,
    speed: 0
  }
});

That should solve the error. I'd recommend getting the correct type from the library instead of duplicating it as I did in the code snippet.

Amiratak88
  • 1,204
  • 12
  • 18
1
const [dataLoc, setDataLoc] = useState<{
  date: string;
  coords: GeoCoordinates;
}>({
  date: '', 
  coords: {} as GeoCoordinates,
});
/*
 * Your another codes
 */

//calling it everwhere you want (e.g in useEffect)
const _setLocation = () => {
  //checking location permission then
  Geolocation.getCurrentPosition(
    ({timestamp, coords}) => {
      const date = dateToString(timestamp);
      setDataLoc({date, coords});
    },
    e => console.log(e),
  );
};
/*
 * Your another codes
 */
return (
  <Text style={styles.data}>
    {dataLoc.coords?.latitude}
  </Text>
);
MHP
  • 577
  • 5
  • 9