Something annoying about promises

Here’s something I noticed when coding in Visual Studio Code and returning an object from a promise.
Suppose I have the following function…

getSomething()
  {
    return new Promise(function(resolve, reject)
    { firebase.database().ref('something').once('value')
      .then((req)=>{resolve(req.val())})
      .catch((err)=>{reject(err)})
    });
  }

and it returns the JSON object

{
id:1,
name:'Bob'
}

Then in another page, I call the function like this…

getSomething().then((c)=>{
console.log(c.name);//red lines appear here, showing "property 'name' does not exist on type {}"
})

The code runs fine and displays the name, but VS Code shows a red line under the “c.name”, and mousing over it, it says property ‘name’ does not exist on type {}.

I find it annoying because I don’t want any red lines on any of my code pages.

The only way I could resolve this is to define another variable and assign it to c, then access the attributes from it. In other words…

var obj;// The variable

getSomething().then((c)=>{
obj = c;
console.log(obj.name);//no errors!!
})

Any idea why this is so? Is there a better way to code this?

Thanks.

I don’t have VS Code but you could probably solve that by defining and giving a type for c

like

export interface Something {
      name: string;
 }

 getSomething().then((c: Something)=>{

or you could too using classes

export class Something {
   name: string;
}

also in your getSomething method

getSomething(): Promise<Something> {
  ....
}

or in worst case use any

 getSomething().then((c: any)=>{

The last one (C: any) worked. Thanks!

The point of the red lines is to warn you when you’re making a mistake. Getting rid of them with any completely defeats the purpose of having typing in the first place.

Hello,

typescript brings types to javascript. Using variables with out decaring and typing (or as any) is imho a dirty way, it brings pain if something not working as expected,

Maybe you should got the first way, In long term life is much easier.

Best regards, anna-liebt

1 Like

Cool nice to hear any is the reason. But note, it’s a general bad practice to use any respectively it would be better to define a type like describe above with interface or classes in order to avoid bugs and problem on the long term

1 Like

If u want to do the improper properly, do:

c['name']

Then u dont need any either

:grinning::grinning::grinning:

So the general consensus is to define and use classes/type, rather than generically use ‘any’. Thanks, I’m still getting used to Typescript. So how do you handle custom types? Do you create them in a subfolder inside /src/ and then import in respective pages?

Declaring them alongside whatever service provider provides them is probably most conventional:

export interface Person {
  name: string;
}

@Injectable() export class PersonService {
  allPeople(): Observable<Person[]> { ...}
}

Additionally, if you do insist on using a Promise instead of an Observable, do not explicitly instantiate it as you are. Instead use the toPromise operator.

@obinnae like @rapropos explained, you could declare your class or interfaces in any providers. But you could also declare them in separate file, as you want. For example, in my app I have something like

src/providers/model

where I declare my custom objects. For example let say a model for a user, I will then have

src/providers/model/user/user.ts

which contains something like

export interface User {
   id: string;
}

this object could then be use like

 this.something().then((user: User) => {});

or declared in a page for example

export class MyPage() {
   
   user: User;

}

if you want to user class instead of interfaces that also possible, the advantage is that you could use constructor then, for example

export class User {
   id: string;
  
  constructor() {
    this.id = 'default';
  }
}

which could be then use like

 let user: User = new User();
 console.log(user.id); // -> 'default'

Thanks, @reedrichards. Makes sense. I’ll implement it like that.
I’m basically representing objects stored in firebase db. So if I have a Firebase user object like so

\Users\user1\{id:1, name:'Richard'},

in the code I can do something like

var user:User;

firebase.database().ref('users/user1').once('value', (snapshot)=>{
 user = snapshot.val();
 console.log(user.name);
});
1 Like

Hi @rapropos, I’ll look into observables, as I’m more familiar with Promises than Observables.

Observables are promises on steroids

So be carefull handling

Reed, I’m trying to decide whether to use interfaces or classes (or both). Here’s what I’m aiming at…

export class User
{
 id: string;
 name: string;

  constructor(id: string = null)
  { if (id)
     // return User from Firebase where id=id
    else
    // return empty User object
  }

  save(usr:User)
  {
  // save new user to Firebase
  }

  update(id: string, userObj: User)
  {
    // Update Firebase user with userObj where id=id
  }

  delete(id: string)
  {// Delete User where id=id
  }
}

then use it in other pages like so…

var usr:User = new User(6) // to return user whose ID=6

Is that about right, or you have a better solution (perhaps with interface and/or observables)? Sorry I’m still mastering angular/typescript.

Thanks Tom, I’ll keep it in mind.

In angular it normally works out better to have data as a PODO, and then have the actual logic inside of Providers.

For a more concrete example of this, going based on your class example you don’t really have any way of getting a reference to the Firebase object unless you pass it to all of the functions.

So I’d define an interface

interface User {
  id: string;
  name: string;
}

Then create a provider that retrieves & manages them.

1 Like

@obinnae1h class or interface in my point of view it’s up to you or up to your use case

BUT, I would advice to avoid doing return in a constructor. Furthermore, only my point of view, I think it’s not that readable to have a promise/observable initialization in a constructor, I would rather keep the definition as easy and simple as possible