简体   繁体   中英

Generic class as parameter with inner type

I am using Cerialize as Json serializer/deserializer.

My Api connector works this way:

ApiService.get<T>(endpoint:string):Promise<T>

calls

ApiConnectorService.get<ApiResponse<T>>(tClazz:{new():T;}, endpoint:string);

to deserialize, Cerialize uses class parameter:

function Deserialize(json: any, type?: Function | ISerializable): any;

So, when I call ApiService.get<T>(endpoint) , I call ApiConnectorService.get<ApiResponse<T>>(ApiResponse, endpoint) in it.

Problem

I can't provide ApiResponse<T> as tClazz parameter, compiler says

TS1109: Expression expected

Is there a way to provide Generic class with its Generic type as parameter? This way, when I call get<User>() I get a User in an ApiResponse<User> type, at the moment I only get an Object in ApiResponse, which is not whet we need.

Here is the ApiResponse class:

export class ApiResponse<T>{

    @deserialize
    data:T;

    @deserializeAs(ErrorData)
    error:ErrorData;

    @deserialize
    meta:Object;
}

EDIT: Same error if I want to give an array as class parameter:

ApiService.get<Foo[]>(Foo[], '/bar');

TS1109: Expression expected

You cannot, if you look at the transpiled generic class here: Typescript Playground it looses the generics, so in runtime you have no types so you can't get the type of the generic, meaning, in runtime you cannot know what type is your T. You have to pass the class itself as a parameter. You can use the generics for compilation help, but thats the best you can do.

Taking into account that nested generics are not supported, and generics are just compile time construct, I have made a small sample that I hope might be helpful to you:

export class User
{
    private name: string;

    constructor(serializedValue: string)
    {
        this.name = serializedValue;
    }
}

export class ApiResponse<T>
{
    constructor(val: T)
    {
        this.data = val;    
    }

    data:T;

    error:string;

    meta:Object;
}

class ApiConnectorService<T>
{
    public get<U extends ApiResponse<T>>(tClazz: {new(s: string):T;}, uClazz: {new(t: T):U;}, endpoint:string): U
    {
        let val = 'user';//get serializedvalue from endpoint
        return new uClazz(new tClazz(val));
    }
}   

class ApiService
{
    public get<T>(tClazz: {new(s: string):T;}, endpoint:string): T
    {
        let s = new ApiConnectorService<T>();
        return s.get(tClazz, ApiResponse, '123').data;
    }
}

let a = new ApiService();
console.log(a.get<User>(User, '12'));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM