Typescript anropa statisk metod av generisk typ
Jag har en tjänst som jag vill använda för att returnera ett objekt av en specificerad typ byggd från en JSON.
Jag har en klass MyClass som implementerar en statisk klass som definierar en statisk metod FromJSON.
export interface InterfaceMyClass {
static FromJSON(json: any): any;
}
export class MyClass implements InterfaceMyClass {
constructor(){}
FromJSON(json: any): MyClass {
let instance = MyClass.create(MyClass.prototype);
Object.assign(instance, json);
// Some other code specific to MyClass
return instance;
}
}
Jag vet inte hur man anropar den statiska metoden i den generiska klassen som jag har skickat som parameter i min tjänst. Min tjänst ser ut så här:
export class MyService<T extends InterfaceMyClass> {
getObject() {
let json = getExternalJson(...);
return T.FromJSON(json); // <-- How to call static method FromJSON from T class ?
}
}
Jag skulle vilja använda tjänsten på detta sätt:
let service = new MyService<MyClass>();
let myObject = service.getObject(); // <-- Should by an MyClass instance (created by MyClass.FromJSON)
Fråga: Hur kan jag kalla denna T.FromJSON-metod?
Bonusfråga: Vad är ett bra sätt att implementera en statisk metod? Jag tror inte att min FromJSON-metod från MyClass är statisk. Om jag lägger till ordet static före FromJSON säger den här:
[ts] Class 'MyClass' incorrectly implements interface 'InterfaceMyClass'.
Property 'FromJSON' is missing in type 'MyClass'.
Svar #1
Några saker:
(1) Gränssnitt kan inte ha statiska deklarationer, till exempel:
interface MyInterface {
static myMethod(); // Error: 'static' modifier cannot appear on a type member
}
(kod i lekplats)
Sättet att komma runt detta i TypeScript är att definiera ett builder-/konstruktörsgränssnitt:
interface MyInterface {}
interface MyInterfaceBuilder {
new (): MyInterface;
myMethod();
}
(2) Generiska begränsningar är bara tillgängliga vid kompileringstid, men sedan tar kompilatorn bort dem eftersom JavaScript inte stöder det, till exempel:
class MyClass<T extends string> {
private member: T;
constructor() {
this.member = new T(); // Error: Cannot find name 'T'
}
}
kompileras till:
var MyClass = (function () {
function MyClass() {
this.member = new T(); // Error: Cannot find name 'T'
}
return MyClass;
}());
(kod i lekplats)
När man tittar på js-utdata är det tydligt varför kompilatorn kastar felet Cannot find name 'T', eftersom T inte finns någonstans.
För att kringgå allt det där, här är en lösning för dig:
interface IMyClass {}
interface IMyClassBuilder<T extends IMyClass> {
new (): T;
FromJSON(json: any): any;
}
class MyClass implements IMyClass {
static FromJSON(json: any) {
return "";
}
}
class MyService<T extends IMyClass> {
private classToCreate: IMyClassBuilder<T>;
constructor(classToCreate: IMyClassBuilder<T>) {
this.classToCreate = classToCreate;
}
getObject(): T {
let json = getExternalJson(...);
return this.classToCreate.FromJSON(json);
}
}
let service = new MyService(MyClass);
let myObject = service.getObject();
(kod i lekplats)
