Viewed   4.6k times

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'));

 Answers

5

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')!);
Monday, September 5, 2022
 
niru
 
2

Thats kinda tricky to explain:

Date is a class, this means that values of type Date need to be created through a constructor call. In other words, create a class instance with new Date(...).

The Response.json method will only return an object in JSON format, and such doesnt contain an instance of any class, only maps of key:property.

So what you need to do, is to manually convert the value returned from .json() to a Base object. This can be done as follows:

public getSingle = (keys: any[]): Observable<Badge> => {
        return this._http.get(this.actionUrl + this.getKeysUrl(keys))
            .map(r => r.json())
            .map(v => <Badge>{
              badgeNumber: v.badgeNumber,
              authorizationLevel: v.authorizationLevel,
              endOfValidity: new Date(v.endOfValidity)
              // preferably this string should be in ISO-8601 format
             })
            //the mapping step can be done in other ways most likely
            .catch(this.handleError);
}
Monday, August 8, 2022
 
dchai
 
2

The error is very clear and specific

Error: Cannot call a namespace ('moment') at error (/Users/chris/angular-library/node_modules/rollup/dist/rollup.js:185:14)

This is per the ES Module Specification.

That means the following is an invalid way to import moment, or anything you intend to call, because a module namespace object, such as that created by * as ns may not be called.

import * as moment from 'moment';

The correct form is the form that ngc is raising an error on

import moment from 'moment';

Firstly to make this work, you need to specify the --allowSyntheticDefaultImports flag.

tsconfig.json

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true
  }
}

Assuming that ngc will recognize the option, you still have an additional problem to work out.

The flag above is for users of tools such as SystemJS or Webpack which perform the synthesis, allowing such code to typecheck.

As of TypeScript 2.7, you can now specify the --esModuleInterop flag to have the language provide the synthesis as part of the transpilation process.

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true
  }
}

Note that if you are using a version of TypeScript prior to 2.7 and if you are compiling to CommonJS, AMD, or UMD modules (e.g. with --module commonjs) the correct import syntax is rather

import moment = require('moment');

The import = require syntax is a TypeScript specific construct, now largely unnecessary. It exists to acquire both the type and the value of the module exports of an AMD, CommonJS, or UMD module. The "and" is important because a const, var, or let = require invocation only creates a name in the value space not in the type space.

Thursday, November 3, 2022
 
jyl
 
jyl
1

Since getElementById possibly returns null. So you just simply check before using like:

function Portal1({ children }) {
  return portalDiv ? ReactDOM.createPortal(<>{children}</>, portalDiv) : null;
}
Sunday, October 2, 2022
 
5

Whilst result has the potential to return a string, it cannot implicitly cast this to a string as there is a risk of data loss. i.e. ArrayBuffer as string may result in data truncation (would have to test). So you have to explicitly cast it as to tell the compiler "I know what I am doing".

2 approaches to achieve this are:

(string)fileReader.result;
fileReader.result as string;


Folks, Check @Malvolio's answer, it's more complete.
Monday, November 14, 2022
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share