1

I have an error message:

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

enter image description here

I found a solution here but I didn't understand the answers for my problem.

My code is presented like this:

const expectedRole = route.data['expectedRole'];
const token = localStorage.getItem('token');
    
const { userName, roleId } = decode(token);
console.log(roleId);

enter image description here

Edit 2022-02-02

enter image description here

decode method

export class InvalidTokenError extends Error {}

export interface JwtDecodeOptions {
  header?: boolean;
}

export interface JwtHeader {
  type?: string;
  alg?: string;
}

export interface JwtPayload {
  iss?: string;
  sub?: string;
  aud?: string[] | string;
  exp?: number;
  nbf?: number;
  iat?: number;
  jti?: string;
}

export default function jwtDecode<T = unknown>(
  token: string,
  options?: JwtDecodeOptions
): T;

FYI, I copied the code from the project here

3

3 Answers 3

3

This is just the typescript compiler telling you that token may be null. So you need to check that it isn't before using it in the decode function, since decode does not accept a null parameter.

const expectedRole = route.data['expectedRole'];
const token = localStorage.getItem('token');

if (token) const { userName, roleId } = decode(token);
console.log(roleId);

You can also force the typescript compiler to ignore this using !, which says "this variable will be truthy, trust me", but you need to be absolutely sure it will never be null, or you may get a runtime error.

const expectedRole = route.data['expectedRole'];
const token = localStorage.getItem('token');
    
const { userName, roleId } = decode(token!);
console.log(roleId);

Edit

This solution should work regardless, but you should define the correct return types for decode

const expectedRole = route.data['expectedRole'];
const token = localStorage.getItem('token');

if (token) const info: { userName, roleId } = decode(token);
console.log(info.roleId);

OR

const expectedRole = route.data['expectedRole'];
const token = localStorage.getItem('token');

if (token) const info: any = decode(token);
console.log(info.roleId);

Edit 2

Looks like decode is a generic function, so you can define the return type like this:

const expectedRole = route.data['expectedRole'];
const token = localStorage.getItem('token');

if (token) const { userName, roleId } = decode<{ userName, roleId }>(token);
console.log(roleId);
Sign up to request clarification or add additional context in comments.

7 Comments

Thank you, I took the first solution. I just have a little problem with if (token) const { userName, roleId } = decode(token);, I have an error message Property 'roleId' does not exist on type 'unknown' and Property 'userName' does not exist on type 'unknown' I don't understand why it keeps bugging?
What is the return type of decode?
I edited my first post, I put a screenshot at the end of the post with the error, (thanks)
Show me the decode function please
If I'm not wrong, the exclamation mark is discouraged, and token as string should be used instead
|
2

I was able to fix the problem by modifying this:

export class RoleGuard implements CanActivate {

  constructor(
    private authService: AuthService,
    public router: Router
  ){ }
  canActivate(route: ActivatedRouteSnapshot):boolean{
    const expectedRole = route.data.expectedRole;
    const token = localStorage.getItem('token');

const { userName, roleId } = decode(token);
console.log(roleId);

if( !this.authService.isAuth() || roleId !== expectedRole){
  console.log('Usuario no autorizado para la vista');
  this.router.navigate(['login']);
  return false;
}
return true;
  }  
}

To this:

export class RoleGuard implements CanActivate {

  constructor(
    private authService: AuthService,
    public router: Router
  ) { }
  canActivate(route: ActivatedRouteSnapshot): boolean {
    const expectedRole = route.data['expectedRole'];
    const token = localStorage.getItem('token');

    if (!this.authService.isAuth()) {

      console.log('Usuario no autorizado para la vista');
      this.router.navigate(['login']);
    };
    const info: { userName: string, roleId: string } = decode(token);
    if (info.roleId != expectedRole) {
      console.log('Usuario no autorizado para la vista');
      this.router.navigate(['login']);

      return false;
    }
    return true;
  }
}

I separated the if into two ifs, each one performing an independent activity.

Comments

0

Thinking like typescript thinks, you need to define a type (i.e. "string", "number", "void") for variables as well as functions or methods.

Ones you have defined type for variables (or for methods), typescript check if its type match with its definition.

In your case token is probably null and typescript alert you that string not match with null and rise an error.

So you need to debug token and check if:

  • is not null nor undefined
  • is a string

In some cases you need to declare type of variable in the following way:

token: string = ...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.