Typescript llama a método estático de tipo genérico
Tengo un servicio que quiero usar para devolver un objeto de un tipo especificado construido a partir de un JSON.
Tengo una clase MyClass que implementa una clase estática que define un método estático 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;
}
}
No sé cómo llamar al método estático de la clase genérica que he pasado como parámetro en mi servicio. Mi servicio se ve así:
export class MyService<T extends InterfaceMyClass> {
getObject() {
let json = getExternalJson(...);
return T.FromJSON(json); // <-- How to call static method FromJSON from T class ?
}
}
Me gustaría usar el servicio de esta manera:
let service = new MyService<MyClass>();
let myObject = service.getObject(); // <-- Should by an MyClass instance (created by MyClass.FromJSON)
Pregunta: ¿Cómo puedo llamar a este método T.FromJSON?
Pregunta adicional: ¿Cuál es la buena manera de implementar un método estático? No creo que mi método FromJSON de MyClass sea estático. Si agrego la palabra static antes de FromJSON, me dice esto:
[ts] Class 'MyClass' incorrectly implements interface 'InterfaceMyClass'.
Property 'FromJSON' is missing in type 'MyClass'.
Respuesta #1
Unas cuantas cosas:
(1) Las interfaces no pueden tener declaraciones estáticas, por ejemplo:
interface MyInterface {
static myMethod(); // Error: 'static' modifier cannot appear on a type member
}
(código en el área de pruebas)
La forma de evitar esto en TypeScript es definir una interfaz de constructor/constructor:
interface MyInterface {}
interface MyInterfaceBuilder {
new (): MyInterface;
myMethod();
}
(2) Las restricciones genéricas solo están disponibles en tiempo de compilación, pero luego el compilador las elimina ya que JavaScript no las soporta, por ejemplo:
class MyClass<T extends string> {
private member: T;
constructor() {
this.member = new T(); // Error: Cannot find name 'T'
}
}
se compila en:
var MyClass = (function () {
function MyClass() {
this.member = new T(); // Error: Cannot find name 'T'
}
return MyClass;
}());
(código en el área de juegos)
Al observar la salida de js, está claro por qué el compilador arroja el error No se puede encontrar el nombre 'T', ya que T no se encuentra por ningún lado.
Para evitar todo eso, aquí tienes una solución para ti:
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();
(código en el área de juegos)
