Existe uma maneira de adicionar métodos dinamicamente a uma classe usando TypeScript?
-
12-12-2019 - |
Pergunta
Estou tentando criar algum tipo de método mixin que adicione métodos ao protótipo/classe instantaneamente, mas recebo erros como
A propriedade 'GreetName' não existe no valor do tipo 'cumprimentador'
e
A propriedade 'GreetName' não existe no valor do tipo 'cumprimentador'
quando executo o código a seguir.
class Greeter {
greeting: string;
constructor (message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
Greeter.prototype.greetName = function(name){
return this.greet() + ' ' + name;
}
var greeter = new Greeter('Mr');
window.alert(greeter.greetName('Name'));
Na verdade, ele compila para js válido e é executado conforme o esperado.Existe uma maneira de fazer isso sem avisos/erros do compilador?
Solução
Esta solução tem a vantagem de fornecer verificação de tipo quando você adiciona um método dinamicamente:
class MyClass {
start() {
}
}
var example = new MyClass();
// example.stop(); not allowed
interface MyClass {
stop(): void;
}
MyClass.prototype['stop'] = function () {
alert('Stop');
}
var stage2 = example;
stage2.stop();
Outras dicas
Eles precisariam de um conceito de classes parciais para que isso funcionasse, o que atualmente não é suportado.Vou lhe dizer que o que descobri que funciona melhor para esses tipos de cenários é usar interfaces (estou programando em TypeScript há cerca de 6 meses - estou na MS, mas não na equipe TypeScript)
As interfaces são extensíveis simplesmente definindo os métodos que você está adicionando à interface.Como exemplo disso, se você instalar um plug-in jQuery, você desejará redefinir a interface IJQuery e IJQueryUtil para incluir métodos adicionais do plug-in.Desse ponto em diante, você pode invocar os métodos dos plugins através de $.plugin() e o TypeScript ficará feliz.
Existe outra maneira de fazer isso.
Greeter["SomeProperty"] = function() {
return "somevalue";
};
Funciona da mesma forma e usa a função indexadora de propriedades em javascript e o typescript não reclama.
Semelhante ao exemplo do @Fenton, mas sem as coisas complicadas:
class MyClass {
start() {
}
}
MyClass.prototype['stop'] = function () {
alert('Stop');
}
interface MyClass {
stop(): void;
}
var example = new MyClass();
example.stop(); // Allowed!!!
É assim RxJS
faz isso
import {Observable} from "./observable"; // which is Greeter in your case
declare module "./observable" {
interface Observable<T> {
map<U>(f: (x: T) => U): Observable<U>;
}
}
Observable.prototype.map = function (f) {
}
Isso é chamado de Aumento de Módulo.
Depois de implementar métodos e propriedades dinâmicas nas classes, esta foi a solução que consegui para evitar que o compilador Typescript reclamasse:
...
window.alert(greeter['greetName']('Name'));
Basicamente, use o método de colchetes de acessadores de propriedade.