deblockt / hal-rest-client

Typescript HAL Rest client
Apache License 2.0
25 stars 11 forks source link

Fetch Generic model data? #8

Closed EvgeniyReznichenko closed 7 years ago

EvgeniyReznichenko commented 7 years ago

Hi Thomas,

One of my API endpoints returns me a set of similar structures which i'd like to map on my custom client side HAL resource model.

The output structure is looks like below:

data:
     set1:
           count: 3
           list: [type1, type1, type1]
     set2:
           count: 2
           list: [type2, type2]
     set3:
           count: 4
           list: [type3, type3, type3, type3]

So, I've tried to to map such a structure on the following kind of model:

class InfoSet<T extends HalResource> extends HalResource {
    @HalProperty()
    count: number;

    @HalProperty(T) <---- ERROR: 'T' only refers to a type, but is being used as a value here
    list: T[];
}

export class Data extends HalResource {
    @HalProperty(InfoSet)
    set1: InfoSet<Type1>;

    @HalProperty(InfoSet)
    set2: InfoSet<Type2>;

    @HalProperty(InfoSet)
    set3: InfoSet<Type3>;
}

But it shows an error as displayed above at 5th row

So I've tried to workaround that as like that:

class InfoSet<T extends HalResource> extends HalResource {
    test: T;

    @HalProperty()
    count: number;

    @HalProperty(typeof this.test) <--- No more error
    list: T[];
}

After that there were no any compile time issues anymore, but on application open , i've got the next error in browser console: image

Where DashboardInfo is the same InfoSet but in my real app.

But T already extends HalResource type..

Is it possible to map response data on typescript generic HAL models? If yes, what am i doing wrong?

Regards, Evgeniy

deblockt commented 7 years ago

I'm sorry, but i think that is not possible. On transpilation time, generic type are removed. After transpilation write InfoSet<Type1> is same as InfoSet.

This error <---- ERROR: 'T' only refers to a type, but is being used as a value here is showed because T is a type, not a value accesible on runtime.

use typeof this.test can't work. typeof return a string by analysing var value to get type. on runtime this.test is undefined, so typeof this.test return "undefined".

You have no option to work like this. Furthermore anotation are executed on class initialisation, not on object construction, so i can't access to generic type specified on Data class.

I'have not tested, but i think that you can use inheritance to write less code. Somthing like this :

abstract class InfoSet<T extends HalResource> extends HalResource {
    @HalProperty()
    count: number;

   /**
     * HalProperty defined on subclass
     */
    list: T[];

    // other functions ... and properties
}

class InfoSetType1 extends InfoSet<Type1> {
    @HalProperty(Type1) 
    list: Type1[];
}

... 

export class Data extends HalResource {
    @HalProperty(InfoSetType1)
    set1: InfoSet<Type1>;

    ...
}

I do not know if it can work, but that's the only solution I can imagine.

EvgeniyReznichenko commented 7 years ago

Thanks for the detailed explanation! I did almost the same as you suggested above

Regards, Evgeniy