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