Version 4.6.4 of TypeScript is flagging the code as invalid

How can I fix this Typescript problem?

const userInformation: {
      email: string;
      id: string;
      _token: string;
      _tokenExpirationDate: string;
    } = JSON.parse(localStorage.getItem('userData'));

https://i.sstatic.net/xMh9P.png

Console Error Message

Error: src/app/auth/authservice.ts:56:20 - error TS2345: Argument of type 'string | null' is not assignable to parameter of type 'string'.
Type 'null' is not assignable to type 'string'.

I included the // @ts-ignore but WebStorm keeps showing an error.

Answer №1

Let's overlook the fact that JSON.parse() has a call signature declaration that returns the unsafe any type. For now, let's assume that if JSON.parse() doesn't return null, it will be a value of your expected object type.


There is a possibility that

localStorage.getItem("userData")
could be null, and TypeScript considers it an error to call JSON.parse(null) because the purpose of JSON.parse() is usually to parse strings encoding JSON values. While parsing null isn't a runtime error in JavaScript, it's a type error according to TypeScript. Refer to What does "all legal JavaScript is legal TypeScript" mean? for further details.

To make it more type safe, ensure only a string is passed like this:

const retrievedValue = localStorage.getItem('userData');
const userData = retrievedValue ? JSON.parse(retrievedValue) as {
  email: string;
  id: string;
  _token: string;
  _tokenExpirationDate: string;
} : null;

This compiles without errors, and now userData holds the type {email: string ... } | null, reflecting the union with the null type indicating that userData can be either a valid object or null.


If you prefer expediency over safety, you can deceive the compiler about the local storage result and assert that it's not null using the non-null assertion operator (!):

const userData: {
  email: string;
  id: string;
  _token: string;
  _tokenExpirationDate: string;
} | null = JSON.parse(localStorage.getItem('userData')!);

Note that the | null was manually added since the compiler no longer sees that possibility.

Playground link to code

Answer №2

If you're looking for a simple solution to your problem, I suggest doing the following:

const userData: {
  email: string;
  id: string;
  _token: string;
  _tokenExpirationDate: string;
} = JSON.parse(localStorage.getItem('userData') ?? "null");

Take note that the nullish coalascing operator (??) requires typescript 3.7.


If you want the type to account for the possibility of being null (in case 'userData' does not exist in localStorage), using a union type with null would be appropriate:

const userData: {
  email: string;
  id: string;
  _token: string;
  _tokenExpirationDate: string;
} | null = JSON.parse(localStorage.getItem('userData') ?? "null");

At this stage, it might be beneficial to define the userData type as an interface:

interface UserData {
  email: string;
  id: string;
  _token: string;
  _tokenExpirationDate: string;
}

const userData: UserData | null = JSON.parse(localStorage.getItem('userData') ?? "null");

Answer №3

If there is no assigned value in the localstorage, we can simply assign an empty string directly

let userStoredData = JSON.parse(localStorage.getItem('userData') ?? '');

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to wrap `useFetch` in order to leverage reactivity?

When I wrap useFetch() as a composable to customize the baseURL and automatically set an authentication token, I encounter reactivity issues when calling the composable within a component without using the await keyword. Typically, I would call const { dat ...

Implementing dynamic keys in a JSON data structure with Node.js

Specifically focused on utilizing Node.js ES6 capabilities. I am currently working on creating a JSON document for insertion into a MongoDB database. The keys for inserting the document will be derived from the input values provided. For instance, Here i ...

Re-rendering components using arrow functions

Using an arrow function, I have implemented a feature to toggle a div and show/hide a button based on the div's visibility. toggleDeliveryDiv = () => { document.getElementById('btn_collapse_delivery').click(); this.s ...

Utilize the useRef hook to dynamically retrieve the updated height when children are altered

I am working with an accordion component and using the useRef hook to measure the height of the children. However, I noticed that when I update the content of the children dynamically, the height measurement does not get updated unless I click on the toggl ...

I am dynamically generating table rows and populating them with data. However, I encountered an issue with retrieving the data by their respective IDs

Creating a table row dynamically by populating it with data. However, encountering an issue with retrieving the data by their respective id. if(xmlhttp.status == 200) { var adminList = xmlhttp.responseJ ...

Cypress error: Unable to access 'uid' property as it is undefined

Recently in my Cypress project with TypeScript support utilizing the Cucumber Preprocessor, an unexpected exception has started appearing: TypeError: Cannot read properties of undefined (reading 'uid') There are instances where changing to a di ...

Trouble with useEffect not triggering in NextJS 13.4 (app router) application

When trying to fetch data from the next API route, I encountered an issue where the useEffect method did not trigger on page reload. Additionally, I was unable to make this component async as Next.js does not allow async functions in client components. pa ...

Exploring the world of cookie security with SameSite and Secure features in ExpressJS

Despite having the specified settings on my express application, a warning keeps appearing in the console. Has anyone encountered this error before? I found some information related to it here: https://github.com/expressjs/express/issues/3095 The version ...

What is the best way to add hidden columns in Telerik Grid MVC3?

I'm currently working with a grid where I need to hide certain columns using the following code: foreach (var attr in grid.Attr) .Columns(columns => { columns.Bound(attr.key) .Width(attr.width) .Visible(attr.isVisi ...

Is it possible to implement typed metaprogramming in TypeScript?

I am in the process of developing a function that takes multiple keys and values as input and should return an object with those keys and their corresponding values. The value types should match the ones provided when calling the function. Currently, the ...

Utilize AJAX and jQuery to seamlessly submit a form

I am attempting to use jQuery and AJAX to submit a form in order to add a row to a table called cadreSante (which is in French). The code I am using for this operation is provided below. Can someone please identify any errors in the code and suggest ways t ...

Rendering in Angular 2 is exclusively done through the use of arrow functions

Is Angular 2 only rendering using arrow functions, or am I missing something? this.service.getData(o).subscribe(res => { this.data = res.data this.view = res.view }); It actually renders my component, but this.service.getData(o).subscribe(functi ...

Is there a way to modify the color of the horizontal line within react-native-otp-inputs in the React Native platform?

Is there a way to customize the color of the horizontal line in react-native-otp-inputs for react native? I used react-native-otp-inputs to capture user OTP input, but now I want to change the color of the default black horizontal line to white. You can re ...

The API request is experiencing delays due to the large dataset of 250,000 records

Utilizing API calls to retrieve data for the frontend is essential, but with a database table containing 250,000 rows, efficiency becomes a concern. In my .NET Core application, I implement the following query: IQueryable<Message> query = context.Me ...

Exploring CouchDB through Ajax to interact with a static website

Is it feasible for my HTML static website to interact with CouchDB using AJAX and retrieve the data without relying on server-side languages like PHP or Python? The CouchDB might be hosted on a different server/domain, so JSONP would need to be utilized. ...

What is the best way to establish anchors for *ngFor elements in Angular 2 and beyond?

I have a component that displays items using *ngFor. My goal is to scroll down to the element with anchor #3. Here's the code snippet: @Component({ selector: 'my-app', template: ` <button (click)="scroll(3)">scroll 2</butt ...

Is there a way to trigger an ajax call specifically on the textarea that has been expanded through jQuery?

Whenever I expand a textarea from three textareas, all three trigger an ajax call. Is there a way to only call the ajax for the specific expanded textarea? I tried using $(this).closest('textarea').attr('id'), but it didn't work. A ...

view multiple HTML documents simultaneously in a single browser tab

Currently, I am in the process of building a wiki and have included tables in various sections. I want to showcase these tables on the main page as well. Rather than constantly copying and pasting them, I'm looking for a way to have the main page auto ...

Declaring types in NGRX Effect V10 has changed since classes are no longer used, causing types to not be inferred as easily

After the V10 upgrade to NGRX, there seems to be a change where passing a type of Action to the effect is no longer possible. As Actions are now declared as functions instead of classes, I'm wondering if there's still a way to handle this in V10? ...

Creating a customized bundle with Bootstrap using the Rollup tool

In the official Bootstrap 5 documentation, it mentions that we can import pre-compiled js files from bootstrap/js/dist and create a custom bundle using tools like Webpack or rollup. https://getbootstrap.com/docs/5.0/getting-started/javascript/#individual- ...