Home > Mobile >  Typescript typecasting fails on run time but ok during build
Typescript typecasting fails on run time but ok during build

Time:06-13

i have a Typescript class responsible for storing and retrieving any object, its type as well as the date when the object was stored in LocalStorage (code below)

Problem is the "storageDate" property. Though during compile time, TS mentions the type to be "Date" but at runtime its a string. So i can not use for eg toDateString() function on storageDate. Any idea why this is happening and suggestions on how to write it?

//Class

export interface ILocalStorageReturnValue<T>{
  storageDate:Date;
  storedObj:T
}

export class LocalStorage<T> implements ILocalStorage<T>
{
  
  constructor(){
    if( !window.localStorage)
      throw new Error(`[${constants.FrameWorkName}.LocalStorage]:${strings.ErrBrowserNoLclStrg}`)
  }

  
  public setItem(key: string, val: T): void{
    if(!key || !val )
    throw new Error(`[${constants.FrameWorkName}.LocalStorage.setItem]:${strings.ErrMissingKeyValProp}`)

    const newObj:ILocalStorageReturnValue<T> = {
      storedObj: val,
      storageDate: new Date()
    }

    window.localStorage.setItem(key ,JSON.stringify(newObj))

  }

  public getItem(key: string): ILocalStorageReturnValue<T> | null{


    return  JSON.parse( window.localStorage.getItem(key)) ? <ILocalStorageReturnValue<T>>JSON.parse( window.localStorage.getItem(key)):null
    
  }
}

// access

const ls = new LocalStorage<IImage>().getItem(constants.localStorageKey)
ls.storageDate().toDateString() --> throws an error saying toDateString is not a function .

CodePudding user response:

The problem is that your code doesn't ensure the shape of the object is correct when you retrieve it from local storage. JSON doesn't have any concept of dates, but you're returning the result of JSON.parse (without any reviver function) and telling TypeScript that that is a ILocalStorageReturnValue<T>. But it isn't one, because ILocalStorageReturnValue's storageDate is a Date, and JSON.parse (without a reviver function) will never create a Date. You have to do that in your code. The type assertion¹ is incorrect, but TypeScript trusts what you tell it.

Since you're relying on the default handling of dates when you store the item, the storageDate string in local storage will be compatible with new Date, so you could do this:

public getItem(key: string): ILocalStorageReturnValue<T> | null {
    const str = window.localStorage.getItem(key);
    if (!str) {
        return null;
    }
    const result = JSON.parse(str);
    result.storageDate = new Date(result.storageDate);
    return result;
}

Playground link


¹ Note that TypeScript doesn't have casting, it has type assertions. A type assertion is purely a compile-time thing. It's you telling TypeScript the type of something that it may not be able to figure out the type of. Type assertions have no effect whatsoever at runtime.

  • Related