Reputation: 3959
I am trying create some kind of mixin method that add methods to the prototype/class on the fly but I get errors such as
The property 'greetName' does not exist on value of type 'Greeter' any
and
The property 'greetName' does not exist on value of type 'Greeter' any
when I run the following code.
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'));
It actually compiles to valid js and runs as expected. Is there a way to do this with out compiler warnings/errors?
Upvotes: 40
Views: 44979
Reputation: 28600
This is how RxJS
does it
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) {
}
This is called Module Augmentation.
Upvotes: 4
Reputation: 251242
This solution has the benefit of giving you type checking when you dynamically add a method:
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();
Upvotes: 33
Reputation: 584
Similar to @Fenton example, but without the gnarly stuff:
class MyClass {
start() {
}
}
MyClass.prototype['stop'] = function () {
alert('Stop');
}
interface MyClass {
stop(): void;
}
var example = new MyClass();
example.stop(); // Allowed!!!
Upvotes: 3
Reputation: 1
After having to implement dynamic methods and properties on classes, this was the solution I was able to go with to prevent Typescript compiler from complaining:
...
window.alert(greeter['greetName']('Name'));
Basically, use the bracket method of property accessors.
Upvotes: 0
Reputation: 3547
There is another way to do this.
Greeter["SomeProperty"] = function() {
return "somevalue";
};
Works the same and uses the property indexer function in javascript and typescript doesn't complain.
Upvotes: 8
Reputation: 1946
They would need a concept of partial classes for this to work which currently isn't supported. I'll tell you that what I've found works better for these types of scenarios is to use interfaces instead (I've been programming in TypeScript for about 6 months now - I'm at MS but not on the TypeScript team)
Interfaces are extensible after the fact by simply definging the methods you're adding to the interface. As an example of this, if you install a jQuery plugin you'll want to re-define the IJQuery & IJQueryUtil interface to include the plugins additional methods. From that point forward you can invoke the plugins methods through $.plugin() and TypeScript will be happy.
Upvotes: 8