Declare (define) Class member methods

10,389

A bit late, but I had a similar requirement when converting parts of a legacy system to TypeScript, so this might help somebody else.

If you know your class will be enhanced at runtime with other methods and you simply want to have type information and intellisense available for those methods, AND you don't want to write ugly stubs, you can try this:

First, define your interface(s) detailing the runtime methods:

interface RuntimeImplementedType {
    public method(): void;
}

interface AnotherRuntimeImplementedType {
    public other_method(): void;
}

Then define a variable whose type is specified as a constructor function returning the union of the types that you want to inform TypeScript your class implements at runtime. Assign the variable a function returning an empty object literal, casting to "any" so as to avoid compiler grumbles and ensure that when transpiled, what is actually being extended is just a plain old empty object.

const Base: new() => RuntimeImplementedType & AnotherRuntimeImplementedType = (() => {}) as any;

Now define your new class, extending from your constructor function variable:

class Classic extends Base {
    public doSomething() {
        this.method();
        this.other_method();
    }
}

All methods from the interfaces should be available, but without having to actually provide an implementation.

Share:
10,389

Related videos on Youtube

Rudolf Gröhling
Author by

Rudolf Gröhling

My hovercraft is full of eels.

Updated on June 24, 2022

Comments

  • Rudolf Gröhling
    Rudolf Gröhling almost 2 years

    I have TypeScript ES6 Class, suppose it looks like this

    class Classic
        private _member: Object;
        constructor(member: Object) {
           this._member = member;
        }
    }
    

    And I have some rich object, that contains a lot of methods, which I want to inherit, but that object is not a TS or ES6 Class, it's just POJO (ObjectLiteral).

    So I made quick and dirty inheritance like

    Object.assign(Classic.prototype, ObjectLiteralWithMethods);
    

    No need for deep copy, everything works.

    How can I tell TypeScript that Classic has these inherited methods and specify their behavior?

    I searched for keywords like declare OR define AND class AND method, but my google-fu is not sufficient.

    I tried define interface for Classic, but it did not work either.

    I tried to declare class like

    declare class ObjectLiteralWithMethods {
        public method(): void;
        protected _method(parameter: string): void;
    }
    

    and then extend that declaration like

    class Classic extends ObjectLiteralWithMethods { ... }
    

    but then TypeScript wants me to call super() in constructor, which fails.

    I know that I can implement "dummy" methods on Classic like

    class Classic {
        dummyMethodImplementation(param: string): string {
            return param;
        }
    }
    

    but this would be painfull and inefficient. I just want to define/declare that class Classic is extended.

    SOLVED

    Sort of...

    The ObjectLiteralWithMethods in my case was actually a prototype for jQuery widget. So, I extended the owner of the prototype.

    It needed some patching, because TS was not aware of the owner so I made:

    // declaring the properties and methods which will be inherited by my class
    declare class JQueryUIWidget {
        public property: string;
        public method(): string;
        ...
    }
    
    // must declare a constructor for JQueryUIWidget to be able to extend
    // and cast the value to any, so TS do not mind
    const Widget: { new (): JQueryUIWidget } = $.Widget as any;
    
    // and then extend that declaration
    class Classic extends Widget {
        constructor() {
            super(); // super(); is mandatory here, with plain object it 
                     // did not worked, but since Widget is in fact a Function
                     // it works now
        }
    }