json - Generisk klass som parameter med inre typ


Jag använder Cerialize som Json-serialiserare/deserialiserare.

Min API-anslutning fungerar på detta sätt:

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

samtal

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

för att deserialisera använder Cerialize klassparametern:

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

Så när jag kallar ApiService.get<T>(endpoint), kallar jag ApiConnectorService.get<ApiResponse<T>>(ApiResponse, endpoint) i den.

Problem

Jag kan inte tillhandahålla ApiResponse<T> som tClazz-parameter, kompilatorn säger

TS1109: Uttryck förväntat

Finns det ett sätt att ge en generisk klass dess generiska typ som parameter? På så sätt, när jag anropar get<User>() får jag en User i en ApiResponse<User>-typ, för tillfället får jag bara ett Object i ApiResponse, vilket inte är vad vi behöver.

Här är ApiResponse-klassen:

export class ApiResponse<T>{

    @deserialize
    data:T;

    @deserializeAs(ErrorData)
    error:ErrorData;

    @deserialize
    meta:Object;
}

REDIGERA: Samma fel om jag vill ge en array som klassparameter:

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

TS1109: Uttryck förväntat

Svar #1

Du kan inte, om du tittar på den transpilerade generiska klassen här: Typescript Playground, den förlorar generikerna, så i runtime har du inga typer och kan därför inte få typen av den generiska, vilket betyder att du i runtime inte kan veta vilken typ din T är. Du måste skicka klassen själv som en parameter. Du kan använda generikerna för kompileringens hjälp, men det är det bästa du kan göra.

Svar #2

Med tanke på att nästlade generics inte stöds, och att generics bara är en konstruktion vid kompileringstid, har jag gjort ett litet exempel som jag hoppas kan vara till hjälp för dig:

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'));