0

I would like my javascript data to be like this:

"dogs": {
    "ada": {
        age: 7,
        breed: poodle
    },
    "levin": {
        age: 5,
        breed: shitzu
    },
    ...
}

Where the name is an object key. I have this typescript class:

export class Dog {
  [dogName: string]: DogDetails;
}

The only way I could see that I could encapsulate methods to create accesssors is by adding these static methods to Dog:

  public static getDogName(dog: Dog): string {
    return Object.keys(dog).toString();
  }

  public static getDogDetails(dog: Dog): DogDetails {
    return dog[Dog.getDogName(dog)];
  }

Which is pretty horrible. One reason being is that static access is required:

Dog.getDogName(dog)  // this is how it must be done

And seems so contrary to how this should be written, which would be:

dog.getName();  // this unfortunately can't be done

The situation would be much nicer if there was a way to get access to the index signature value. However I could not find any way to achieve this. Is there a way or is there a better way to write this class?

Note that this is not possible with classes using index signatures:

public getName(): string {   // this won't work
    Object.keys(this).toString();
}

Since it complains Property 'getName' of type '() => string' is not assignable to string index type 'DogDetails'


Update after answer from @amiramw and comments conversation:

The angular component where this is being used is:

<ion-list *ngFor="let dog of dogs">
    <ion-item>
      <ion-avatar item-start>
        <img src="assets/img/dog.jpg"/>
      </ion-avatar>
      <h4>{{Dog.getName(dog)}}</h4>
      <p>{{Dog.getDogDetails(dog).breed}}</p>
    </ion-item>
  </ion-list>

After the feedback it seems I'll need to write:

<ion-list *ngFor="let dogName of getDogNames()">
    <ion-item>
      <ion-avatar item-start>
        <img src="assets/img/dog.jpg"/>
      </ion-avatar>
      <h4>{{dogName}}</h4>
      <p>{{getDogDetails(dogName).breed}}</p>
    </ion-item>
  </ion-list>

Where getDogNames() is:

  public getDogNames(): string[] {
    if (this.dogs) {
      return Object.keys(this.dogs);
    } else {
      return new Array<string>();
    }
  }

And getDogDetails() is:

  public getDogDetails(name: string): DogDetails {
    return this.dogs[name];
  }

Which works but isn't what I was looking for. I will give @amiramw credit for the suggestion as to a solution to my overall problem.

However I'd much appreciate knowing if there is a way to obtain the typescript index signature value??

1 Answer 1

1

You can create an interface for each dog's data and define a map from string to that interface. The interface can be named (for reuse) or anonymous:

enum Breed {
    poodle,
    shitzu
}
let dogs : { [key:string]: {age: number, breed: Breed} } = {
    "ada": {
        age: 7,
        breed: Breed.poodle
    },
    "levin": {
        age: 5,
        breed: Breed.shitzu
    }
};
Sign up to request clarification or add additional context in comments.

3 Comments

How do you get the name? eg. "ada"
You can get the dogs' list by calling Object.keys(dogs) and then you have the names and you can access each dog data by doing dogs[dogName]. Other option is to maintain the dogs list in an array and add name property to the interface.
Ok I see your approach. I don't think your typescript code is essentially any different to what I have, it is just your approach of accessing the data. This may be how I have to do it, however it is contrary to how I think it should be done and different to text-book cases. I will update my question to qualify with the angular code being used to traverse this data. Thanks for your efforts.

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.