Question

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?

Was it helpful?

Solution

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

OTHER TIPS

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.

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.

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!!!

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.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top