pllee
pllee

Reputation: 3959

Is there a way to add methods on the fly to a class using typescript?

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

Answers (6)

Milad
Milad

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

Fenton
Fenton

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

Schmoo
Schmoo

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

johnrcui
johnrcui

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

James Hancock
James Hancock

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

Steven Ickman
Steven Ickman

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

Related Questions