5

I've been trying to figure out how to do this most of the after noon, and I'm either not getting something, or I'm approaching things wrong.

I'm currently working on a project where I need to override an existing Javascript object for which I have the JS file already.

The 3rd party library has a base class for shapes which is a JS class created as a self executing function.

Within the library, there are a number of shapes that derive from this class, which under the hood look like the use the typical call/apply route to extending the shape base class.

In my code, I have to do this to extend one of the shapes (We'll call it simpleshape) in order to implement my own custom shape and it's drawing code.

function MyCustomShape() {
  simpleShape.call(this);
};

shapeUtils.extend(MyCustomShape, simpleShape);

MyCustomShape.prototype.redraw = function (param1, param2) {
  // my custom implementation here
};

"shapeUtils.extend" is a function within the shape library that extends the class, I don't know what it does exactly, and it's heavily obfuscated. what I do end up with however is a "MyCustomShape" class that implements the simpleShape class an it's properties etc, and as you can see I then just simply override the redraw function, and the graphics library calls that as and when it needs too.

This all works fine in plain old javascript, however I'm working in TypeScript, and currently to get this to work I've in-lined it in an embedded JS function inside the TS class that is to be using it.

Something like:

class myTsClass {

  // constructor

  // private properties, functions etc
  
  private pointerToMyCustomShape: Function;

  private createMyCustomShape(){

    this.pointerToMyCustomShape = function MyCustomShape() {
      simpleShape.call(this);
    };

    shapeUtils.extend(MyCustomShape, simpleShape);

    MyCustomShape.prototype.redraw = function (param1, param2) {
      // my custom implementation here
    };

  }

  private someThingThatUsesTheShapeLibrary()
  {
    this.createMyCustomShape();


    // do stuff that uses the custom shape

  }

}

The problem is, I now need to add some new properties and functions to the override that are now part of the inherited class, and because those properties don't exist in any kind of Typescript definition, typescript refuses to build the project.

For example:

  private createMyCustomShape(){

    this.pointerToMyCustomShape = function MyCustomShape() {
      simpleShape.call(this);
    };

    shapeUtils.extend(MyCustomShape, simpleShape);

    MyCustomShape.prototype.redraw = function (param1, param2) {
      // my custom implementation here
    };

    MyCustomShape.prototype.myCustomFunction = function (param1, param2) {
      // my custom function implementation here
    };

  }

But then trying to do

this.pointerToMyCustomShape.myCustomFunction();

Causes Typescript to throw a wobbler because "Function" doesn't contain a definition for "myCustomFunction".

I can of course, change the type to "any", but then the javascript engine in the browser throws a wobbler, because it's expecting "simpleShape" and "simpleShape" doesn't have a definition for "myCustomFunction"

So, my next plan of attack was to create a class that implemented "myCustomShape" directly in typescript eg:

class MyCustomShape {

  private redraw(param1: type, param2: type)
  {
    // Implementation here
  }

  private MyCustomFunction(param1: type, param2: type)
  {
    // Implementation here
  }

}

thinking because I have some limited D.TS definitions for my 3rd party lib

(Limited because I've created them myself, and not yet converted the entire library, just the bits I'm using)

that I should be able to do

class MyCustomShape extends simpleShapeStatic {

  private redraw(param1: type, param2: type)
  {
    // Implementation here
  }

  private MyCustomFunction(param1: type, param2: type)
  {
    // Implementation here
  }

}

where "simpleShape" is

interface simpleShapeStatic {

  // Properties and functions as implemented in simpleshape
  // according to the docs, here

}

But alas as I've found out, I can't do that.

In the D.TS, iv'e created the stubs as follows:

interface simpleShapeStatic {

  // Properties and functions as implemented in simpleshape
  // according to the docs, here

}

declare var simpleShape: simpleShapeStatic

so I thought I might have been able to use

class MyCustomShape extends simpleShape {

  private redraw(param1: type, param2: type)
  {
    // Implementation here
  }

  private MyCustomFunction(param1: type, param2: type)
  {
    // Implementation here
  }

}

but it appears I cannot do that either.

To complicate things, I'm doing ALL of this using AMD modules, loaded on demand under requireJS, so any class I do derive I need to be able to use by

import customShape = require("myCustomShape");

currently, I'm just going round in circles, so how can I, extend the object's in my JS library, using Typescript, then add my own customisations to them, before then using them in a different typescript class via the import mechanism.

Cheers Shawty

Update - 25/8/2017

For anyone finding this in a google search. I never did find an answer to the question.

No one in SO stepped forward with any clues, and I never found a way to do it while working on the project I was involved in at the time.

Almost a year later, I'm no longer working on this project, and before leaving, because I failed to find a solution, I removed all the code associated with this Q, and just re-wrote the entire thing from scratch in TypeScript.

Update - 20/4/2022

This answer has recently been getting activity again, so a small update is in order.

I finished this contract back in 2017, and I never did find an answer, and as previously commented I did write a LOT of d.ts typescript definitions for the library we where using on the project.

Since I've left however, the library (Called MXGraph) has now been released as open source, and it's creators have re-written it all in Typescript.

MXGraph is also the library that powers https://draw.io/

All of the code and libs for draw.io (Including the legacy MXGraph code that this question was based on) can now be found at:

https://github.com/orgs/jgraph/repositories

shawty
  • 5,729
  • 2
  • 37
  • 71
  • Did you ever figure this out? I'm having the same issue. – Ian Hoar Aug 24 '17 at 17:39
  • Unfortunately not, and since the project was only a contract one, Iv'e now moved on to a diff project. – shawty Aug 25 '17 at 11:36
  • 1
    What I did do however, was to rip out the code I was trying to extend, and replace it with a pure TS solution. In fact, I pretty much wrote an entire d.ts set of definitions for the library in question, but due to the paid nature of the contract was not permitted to release them to the definitely typed project. – shawty Aug 25 '17 at 11:38

1 Answers1

0
class MyClass {
    constructor() {
        Object.assign(this, thirdPartyObject)
    }
}
  • 1
    Please read [How do I write a good answer?](https://stackoverflow.com/help/how-to-answer). While this code block may answer the OP's question, this answer would be much more useful if you explain how this code is different from the code in the question, what you've changed, why you've changed it and why that solves the problem without introducing others. – Saeed Zhiany Jul 07 '22 at 08:10
  • 1
    Thanks for the answer, but this would not have worked way back in early 2016 when I first wrote it. The browser being used back then was IE9, that was the projects baseline standard. Chrome was used for some testing, but even then it had no where near the level of support it does now. Good first effort though, but as @SaeedZhiany said above, the best answers are not just code snippets, great descriptions and background knowledge also go a long way, take a look at some of the answers I've written over the years for some examples. I'm not going to upvote, but I'm not going to downvote either – shawty Jul 07 '22 at 23:18