Published: November 10 2022

Angular - Fix for Argument of type 'string | null' is not assignable to parameter of type 'string'

I just finished updating an Angular 10 project to Angular 14. After migrating the code over to the new project I got the below TypeScript error.

Argument of type 'string | null' is not assignable to parameter of type 'string'.
  Type 'null' is not assignable to type 'string'.ts(2345)


Here's the line that was giving me the error, it didn't like me calling JSON.parse() with the argument localStorage.getItem('user').

this.userSubject = new BehaviorSubject(JSON.parse(localStorage.getItem('user')));


Why did the error appear after updating Angular?

I did a bit of digging and found that my Angular 14 project has the TypeScript strict flag enabled (set to true) whereas my old Angular 10 project did not.

Strict mode in TypeScript

The strict flag enables a bunch of automatic type checking in TypeScript at build time, including the strictNullChecks flag which gives you a type error when you use a possibly null or undefined value where a concrete value (e.g. a string) is expected.

The TypeScript interface for the JSON.parse() function defines a string parameter as the first argument, whereas the interface for localStorage.getItem() defines a return type of string | null. This caused the error because the types don't match.

In Angular 14 the TypeScript base config is located in /tsconfig.json, in Angular 10 it's located in /tsconfig.base.json. For more info on the TypeScript strict flag and related flags see https://www.typescriptlang.org/tsconfig#strict.


How did I fix the TypeScript error?

There are a few ways you can fix the error that I'll go through, but this is the one I ended up going with:

this.userSubject = new BehaviorSubject(JSON.parse(localStorage.getItem('user')!));


All I did was add an exclamation point / bang (!) directly after the parameter to JSON.parse(). It tells the TypeScript compiler not to worry because the parameter will never be null which removes the TypeScript error. I chose this approach because it was the shortest and simplest.

JSON.parse can accept null

The above fix is a bit of a workaround because localStorage.getItem() may in fact return null. However when I tested JSON.parse() in the browser dev console I found that it does work with a null parameter and simply returns null. So in this particular case I think the TypeScript interface is incorrect and the parameter type should be string | null instead of just string.


Alternative fixes to the TypeScript error

Below are a couple of other ways you can fix the above TypeScript error. They are a bit longer but may be more appropriate if your working with a function that really doesn't accept null values.

1. Assign the item from local storage to a variable and only call JSON.parse() if it contains a value.

const item = localStorage.getItem('user');
this.userSubject = new BehaviorSubject(item ? JSON.parse(item) : null);


2. Use the nullish coalescing operator (??) to return the string '{}' if localStorage returns null.

this.userSubject = new BehaviorSubject(JSON.parse(localStorage.getItem('user') ?? '{}'));


TypeScript interfaces for JSON.parse() and localStorage.getItem()

Below are the TypeScript interface definitions for JSON.parse() and localStorage.getItem(). Other methods are omitted for brevity.

JSON.parse TypeScript interface

This is the TypeScript interface for the JSON.parse() function showing the type of the first parameter (text) is string, when testing I found the function also accepts null.

The type definition is located in the /lib/lib.es5.d.ts that comes with the typescript npm package. You can view the source code on GitHub at https://github.com/microsoft/TypeScript/blob/main/lib/lib.es5.d.ts.

interface JSON {
    /**
     * Converts a JavaScript Object Notation (JSON) string into an object.
     * @param text A valid JSON string.
     * @param reviver A function that transforms the results. This function is called for each member of the object.
     * If a member contains nested objects, the nested objects are transformed before the parent object is.
     */
    parse(text: string, reviver?: (this: any, key: string, value: any) => any): any;

    ...
}


localStorage.getItem TypeScript interface

This is the TypeScript interface for the localStorage.getItem() function showing the return type is string | null.

The type definition is located in the /lib/lib.dom.d.ts that comes with the typescript npm package. You can view the source code on GitHub at https://github.com/microsoft/TypeScript/blob/main/lib/lib.dom.d.ts.

interface Storage {
    ...

    /** Returns the current value associated with the given key, or null if the given key does not exist. */
    getItem(key: string): string | null;

    ...
}

 


Need Some Angular Help?

Search fiverr for freelance Angular developers.


Follow me for updates

On Twitter or RSS.


When I'm not coding...

Me and Tina are on a motorcycle adventure around Australia.
Come along for the ride!


Comments


Supported by