mobxjs / serializr

Serialize and deserialize complex object graphs to and from JSON and Javascript classes
MIT License
766 stars 52 forks source link

problem when using generics #63

Closed hassanrazakhalid closed 7 years ago

hassanrazakhalid commented 7 years ago

Hello i am trying to use generics

import {
    createModelSchema,
    primitive,
    reference,
    list,
    object,
    identifier,
    serialize,
    deserialize,
    getDefaultModelSchema,
    serializable,
    alias
} from 'serializr';

export class GenericListResponse<T> {

    @serializable(alias('data', list(object(T)))
    list: T[] = [];
}

But i am getting compilcation error here

[ts] 'T' only refers to a type, but is being used as a value here.
any

And idea how i can achieve this.

alexggordon commented 7 years ago

I apologize, I don't know Typescript that well, but from what I can infer here is data a self referential array of class T?

chengjianhua commented 7 years ago

@hassanrazakhalid

In my opinion, the generic T is just a interface that describes the shape of value.

list: T[] = [];

The above is okay because of this indicates what the shape of a item in list likes.

But object() in serializr is a function that accepts a ModelSchema object or a class which can be found ModelSchema object inside it. Both of them that object() needs are real values not a interface indicates the shape of a value.

I don't know ts that well either ... But I think I understand this correctly.

alexggordon commented 7 years ago

I think I understand. The issue with this example is that you need to instead pass a Class to the object function. You can do this like:

class Response {
    @serializable id;
}

export class GenericListResponse<T> {

    @serializable(alias('data', list(object(Response)))
    list: T[] = [];
}

That list would then hold an array of Response class instances. Does that make sense?

alexggordon commented 7 years ago

Sorry, didn't mean to close this yet!

hassanrazakhalid commented 7 years ago

what i was trying to do is replace T which different of classes when using making api call like against data key. ForExample

deserialize(GenericListResponse<User>,listData)
deserialize(GenericListResponse<Pets>,listData)
deserialize(GenericListResponse<Cars>,listData)

The way you have mentioned will hardcode it with Response and whole point using generic will be lost.

alexggordon commented 7 years ago

So if you have a polymorphism issue then the custom deserializer is your best bet.

class Generic {
    @serializable id;
}

class Cars extends Generic {
   @serializable(list()) cars;
end

export class GenericListResponse<T> {
    @serializable(alias('data', custom(
        dataToSerialize => filterModels.map(filterModel => serialize(dataToSerialize)),
        dataToDeserialize => dataToDeserialize.cars ? deserialize(Cars, dataToDeserialize) : deserialize(Generic, dataToDeserialize) 
    ))) list: T[] = [];
}

that custom function will deserialize with the class Cars when the dataToDeserialize has an attribute cars that is truthy. Is this more what you were referring to?

alexggordon commented 7 years ago

Closed for inactivity