GoGo
GoGo

Reputation: 3077

Argument of type 'string | null' is not assignable to parameter of type 'string'. Type 'null' is not assignable to type 'string'

I have a dotnetcore 20 and angular4 project that I am trying to create a userService and get the user to my home component. The backend works just fine but the service doesn't. The problem is on localStorage. The error message that I have is :

Argument of type 'string | null' is not assignable to parameter of type 'string'. Type 'null' is not assignable to type 'string'.

And my userService

import { User } from './../models/users';
import { AppConfig } from './../../app.config';
import { Injectable } from '@angular/core';
import { Http, Headers, RequestOptions, Response } from '@angular/http';



@Injectable()
export class UserService {
constructor(private http: Http, private config: AppConfig) { }

getAll() {
    return this.http.get(this.config.apiUrl + '/users', this.jwt()).map((response: Response) => response.json());
}

getById(_id: string) {
    return this.http.get(this.config.apiUrl + '/users/' + _id, this.jwt()).map((response: Response) => response.json());
}

create(user: User) {
    return this.http.post(this.config.apiUrl + '/users/register', user, this.jwt());
}

update(user: User) {
    return this.http.put(this.config.apiUrl + '/users/' + user.id, user, this.jwt());
}

delete(_id: string) {
    return this.http.delete(this.config.apiUrl + '/users/' + _id, this.jwt());
}

// private helper methods

private jwt() {
    // create authorization header with jwt token
    let currentUser = JSON.parse(localStorage.getItem('currentUser'));
    if (currentUser && currentUser.token) {
        let headers = new Headers({ 'Authorization': 'Bearer ' + currentUser.token });
        return new RequestOptions({ headers: headers });
    }
}

And my home.component.ts is

import { UserService } from './../services/user.service';
import { User } from './../models/users';
import { Component, OnInit } from '@angular/core';

@Component({
moduleId: module.id,
templateUrl: 'home.component.html'
})

export class HomeComponent implements OnInit {
currentUser: User;
users: User[] = [];

constructor(private userService: UserService) {
   this.currentUser = JSON.parse(localStorage.getItem('currentUser'));
}

ngOnInit() {
   this.loadAllUsers();
}

deleteUser(_id: string) {
   this.userService.delete(_id).subscribe(() => { this.loadAllUsers() });
}

private loadAllUsers() {
   this.userService.getAll().subscribe(users => { this.users = users; });
}

The error is on JSON.parse(localStorage.getItem('currentUser'));

Upvotes: 224

Views: 485315

Answers (14)

sadam hussain
sadam hussain

Reputation: 1

Type 'boolean | undefined' is not assignable to type 'boolean'.
  Type 'undefined' is not assignable to type 'boolean'.ts(2322)

 async jwt({ token, user}) {
            if(user){
                token._id=user._id?.toString();
                token.isVerified=user.isVerified!;
                token.isAcceptingMessages=user.isAcceptingMessages;
                token.usernaenter code hereme=user.username;
            }
            return token
          },

Upvotes: 0

Basil Abbas
Basil Abbas

Reputation: 1802

This simple solution worked for me.

const body = new HttpParams()
    .set('refresh_token', '' + localStorage.getItem('refreshToken'))

Upvotes: 0

Sean Murphy
Sean Murphy

Reputation: 514

A few different answers on here recommend the non-null assertion operator !, or using as string, or (worse) as any (shudder) to type-cast the result for localStorage.getItem(key).

It's important to note that in TypeScript - there is no such thing as a "type conversion." In fact, there is no such thing as a "type" in general. TypeScript is really just syntactic sugar on top of JavaScript to support some loose compile-time illusory "type"-checking. When tsc is done with your code, all you're left with is plain ol' JavaScript with all the type annotations stripped away. This is why things like as and any are dangerous - they allow you to accomplish dumb things like:

const x: number = 5;
const y: string = x as any;
console.log(y); // oops - y is not a string, but the TS compiler thinks it is.

Constructs like ! and as (and any in any sense) are really just instuctions to the TS compiler that state:

Hey Mr. TypeScript compiler - I realize that you think you know some things, but you can take what you think you know, and you can vigorously shove it right up your ol' chocolate-whiz-way. Pucker up, buttercup."

Sometimes when the TS compiler complains, it's doing so for a good reason. We should consider listening instead of resorting to language constructs that effectively turn off the compiler to prevent it from doing what we perceive as "whining."

Relying on things like JSON.parse(localStorage.getItem('currentUser')!) or JSON.parse(localStorage.getItem('currentUser') as string) is a rather bold and risky assertion that currentUser will always and forever return a string value that's actually parsable JSON to some specific TS interface we expect on the guarantee that our app will start blowing smoke in production if it doesn't. This is a bad assumption to make.

I would greatly encourage folks encountering this scenario to embrace the use of the unknown type, use the myriad type-guards available, and please wrap up things prone to unpredictable side-effects like JSON.parse in try...catch error handling such as:

// mock up some storage value and a model interface
localStorage.setItem('currentUser', '{ "userName": "jtest", "displayName": "Joe Test" }');
interface User {
    userName: string;
    displayName?: string;
}


// typeguard to use on whatever unpredictable garbage JSON.parse might return
const isUser = (maybeUser: unknown): maybeUser is User => 
                                     maybeUser instanceof Object
                                     && 'userName' in maybeUser
                                     && typeof maybeUser.userName === 'string';

// get the current user, falling back to 'undefined' if anything blows up
function retrieveCurrentUser(): User | undefined {
    let user: User | undefined;

    try {
        const storageValue = localStorage.getItem('currentUser');
        if (typeof storageValue === 'string') {
            const maybeUser: unknown = JSON.parse(storageValue);
            if (isUser(maybeUser)) user = maybeUser;
        }
    }
    catch {
        // some graceful handling of JSON.parse failing here or 
        // otherwise unable to recover the user from local storage.
    }

    return user;
}

console.log(retrieveCurrentUser());

Upvotes: 0

Weiller
Weiller

Reputation: 21

You can try use the Null coalescing operator ?? in this situation:

this.currentUser = JSON.parse(localStorage.getItem('currentUser') ?? '{}');

Upvotes: 2

Mahmmoud Kinawy
Mahmmoud Kinawy

Reputation: 891

Using Angular or TS:-

JSON.parse(localStorage.getItem('user') as string);

or

JSON.parse(localStorage.getItem('user') as any);

Upvotes: 36

goatstash
goatstash

Reputation: 37

Any ideas for this:

export const useStateWithLocalStorage = (defaultValue: string[], key: string) => {
  const [value, setValue] = useState(() => {
    const storedValues = localStorage.getItem(key);

    return storedValues !== null ? JSON.parse(storedValues) : defaultValue;
  });

  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);

  return [value, setValue];
};

Upvotes: 1

smit agravat
smit agravat

Reputation: 295

I solved it as below

router.navigateByUrl(returnUrl!);

Upvotes: 0

user10374929
user10374929

Reputation: 11

Try this

private userSubject$ = new BehaviorSubject<User | unknown>(null);

Upvotes: 1

Kishor
Kishor

Reputation: 130

  localsetItem: string | null;
  constructor() { 
  this.localsetItem=localStorage.getItem("todos")
  if(this.localsetItem == null)
  {
    this.todos  = [];
  }
  else
      {
    this.todos=JSON.parse(this.localsetItem);
      }
   }

Upvotes: 1

Navi_Programmer
Navi_Programmer

Reputation: 21

Type 'string | null' is not assignable to type 'string'. Type 'null' is not assignable to type 'string'.

export class TodoComponent implements OnInit {
  
  loacalitems!: string;
  todos!: Todo[];

  constructor() {
    this.loacalitems = localStorage.getItem("todos");
}

because localStorage.getItem() return string or null solve this problem any variable this type error is define variable

localitems!: string | null;

this variable holds to type values string or null. then write logic

Short hande if else

this.todos = this.localitems !== null ? JSON.parse(this.localitems) : [];

if-else

if(this.localitems !== null){
   // item not null code
   this.todos = JSON.parse(this.localitems)
}else{
   // item is null code
   this.todos = []
}

Upvotes: 2

Shoaib Khalil
Shoaib Khalil

Reputation: 2420

The non-null assertion operator worked for me very well:

(1). in my case

this.currentUserSource.next(null!)

(2). in your case

this.currentUser = JSON.parse(localStorage.getItem('currentUser')!);

Upvotes: 33

onlyme
onlyme

Reputation: 4052

I have struggled a lot making this issue worked in my case by using the above solution but none of them succeeded. What workied for me is:

   const serializableState: string | any = localStorage.getItem('globalState');
    return serializableState !== null || serializableState === undefined ? JSON.parse(serializableState) : undefined;

I had to cast my variable to string | any and then checked if the variable is null or undefined before parsing it

Upvotes: 0

Duncan
Duncan

Reputation: 95732

As the error says, localStorage.getItem() can return either a string or null. JSON.parse() requires a string, so you should test the result of localStorage.getItem() before you try to use it.

For example:

this.currentUser = JSON.parse(localStorage.getItem('currentUser') || '{}');

or perhaps:

const userJson = localStorage.getItem('currentUser');
this.currentUser = userJson !== null ? JSON.parse(userJson) : new User();

See also the answer from Willem De Nys. If you are confident that the localStorage.getItem() call can never return null you can use the non-null assertion operator to tell typescript that you know what you are doing:

this.currentUser = JSON.parse(localStorage.getItem('currentUser')!);

Upvotes: 451

Willem De Nys
Willem De Nys

Reputation: 949

the accepted answer is correct, just wants to add a newer and shorter answer.

this.currentUser = JSON.parse(localStorage.getItem('currentUser')!);

Upvotes: 94

Related Questions