I have defined a mediator interface:
export class Mediator {
public mediator: any;
setMediator(mediator: any) {
this.mediator = mediator;
}
}
There two classes what I want to use through mediator.
class Pano extends Mediator {}
class Map extends Mediator {
method1() {
this.mediator.setPosition(null);
}
}
Also there is a concrete Mediator class as:
export class MediatorPanoMap
extends Mediator
implements MediatorPanoAction, MediatorMapAction
{
setPosition(coordinate: any) {}
}
Using is:
const mediator = new MediatorPanoMap();
const pano = new Pano();
const map = new Map();
pano.setMediator(mediator);
map.setMediator(mediator);
Problem is I can not get all methods of concrete class to call them:
method1() {
this.mediator.setPosition(null);
}
So, as result I need to call Pano(), Map() methods only throughout Mediator.
Where did I make mistake?
Related
This is something that if I'm able to achieve will be able to design a very easily extendible decorator factory for a project I'm working on.
Basically, I want to be able to use a super class's methods as a decorator for the sub-classes property.
This is usually how decorators work:
import { handleSavePropertyNameDecorator } from "./W-ODecorator"
class Main {
#handleSavePropertyNameDecorator
test1: string = ""
}
export default Main
And then the decorator function:
const propertyNames = [];
export const handleSavePropertyNameDecorator = (_instance: any, propertyName: string) => {
console.log("Executing handleSavePropertyNameDecorator")
propertyNames.push(propertyName);
}
However, instead of defining a separate function for the decorator, I'd like the decorator function to come from the super class:
import SuperClass from "./SuperClass"
class Main extends SuperClass{
#this.handleDecoratorFunction
test1: string = ""
}
export default Main
class SuperClass {
static propertyNameArray: string[] = [];
protected handleDecoratorFunction(_instance: any, propertyName: string) {
console.log("executing handle decorator function from super class!")
SuperClass.propertyNameArray.push(propertyName);
}
}
export default SuperClass;
Currently the keyword "this" has a compilation error that states it's possibly undefined. I've run this code and it doesn't execute the decorator function.
My question is this approach possible with some type of workaround? If this is possible that will significantly improve my organization.
Thank you in advance!
No, you can't do that, the decorator is applied when the class is defined not when it's instantiated. There are no instance methods from your superclass available.
However, you can do this with a static method of course:
class SuperClass {
static propertyNameArray: string[] = [];
protected static handleDecoratorFunction(_instance: any, propertyName: string) {
console.log("executing handle decorator function from super class!")
this.propertyNameArray.push(propertyName);
}
}
class Main extends SuperClass{
#SuperClass.handleDecoratorFunction
test1: string = ""
}
export default Main
In a library that I wish to extend without modifying its code, several classes inherit from the same imported one. That is in this BaseClass I would need to overwrite a specific method.
In the library (written in TypeScript) :
import { BaseClass } from './base_class';
export class ClassA extends BaseClass {}
import { BaseClass } from './base_class';
export class ClassB extends BaseClass {}
…
In the external extension I wish to write :
import { BaseClass } from 'library';
export class ExtendedBaseClass extends BaseClass {
oneMethod() {
const data = BaseClass.prototype.oneMethod.call(this);
// make additional things with data
return data;
}
}
Is there a way for this new ExtendedBaseClass to become the parent of all ClassXs ? At least in a new extended and re-exported version of them without the need to copy their internal code.
Is there a way for this new ExtendedBaseClass to become the parent of all ClassXs?
No.
An alternative might be to replace the one method directly on the base class:
import { BaseClass } from 'library';
const oneMethod = BaseClass.prototype.oneMethod;
Object.defineProperty(BaseClass.prototype, 'oneMethod', {
value() {
const data = oneMethod.call(this);
// make additional things with data
return data;
},
});
There's no way to do exactly what you're asking, but you could achieve the same result by extending each class individually.
ExtendedClassA extends ClassA {
oneMethod() {
// call a shared method if you need to reuse
}
}
// ExtendedClassB, etc
This is my main class (it uses a subclass:)
import SubClass from './SubClass'
class MainClass extends classes(SubClass) {
constructor () {
// some code
}
}
window.MainClass = new MainClass()
export default MainClass
This is the subclass:
class SubClass {
constructor () {
this.someMethod = function () {
// some code
}
}
}
export default SubClass
If I want to use a method from the SubClass I can write: MainClass.someMethod.
How to modify this code so I write: MainClass.SubClass.someMethod instead?
So I can write:
MainClass.SubClass.someMethod
MainClass.SubClass2.someMethod
In case I need another SubClass?
I think you need to call super(). And classes() seem doen't need to be added.
When used in a constructor, the super keyword appears alone and must be used before the this keyword is used.
See document
import SubClass from './SubClass'
class MainClass extends SubClass {
constructor () {
super();
console.log(this.someMethod)
}
}
Hope this help
Based on this awesome Composition over Inheritance video by MPJ, I've been trying to formulate composition in TypeScript. I want to compose classes, not objects or factory functions. Here is my effort so far (with a little help from lodash):
class Barker {
constructor(private state) {}
bark() {
console.log(`Woof, I am ${this.state.name}`);
}
}
class Driver {
constructor(private state) {}
drive() {
this.state.position = this.state.position + this.state.speed;
}
}
class Killer {
constructor(private state) {}
kill() {
console.log(`Burn the ${this.state.prey}`);
}
}
class MurderRobotDog {
constructor(private state) {
return _.assignIn(
{},
new Killer(state),
new Driver(state),
new Barker(state)
);
}
}
const metalhead = new MurderRobotDog({
name: 'Metalhead',
position: 0,
speed: 100,
prey: 'witch'
});
metalhead.bark(); // expected: "Woof, I am Metalhead"
metalhead.kill(); // expected: "Burn the witch"
This resulting in:
TS2339: Property 'bark' does not exist on type 'MurderRobotDog'
TS2339: Property 'kill' does not exist on type 'MurderRobotDog'
What's the right way of doing class composition in TypeScript?
Composition vs Inheritance
I think we should make a distinction between composition and inheritance and reconsider what we are trying to achieve. As a commenter pointed out, what MPJ does is actually an example of using mixins. This is basically a form of inheritance, adding implementation on the target object (mixing).
Multiple inheritance
I tried to come up with a neat way to do this and this is my best suggestion:
type Constructor<I extends Base> = new (...args: any[]) => I;
class Base {}
function Flies<T extends Constructor<Base>>(constructor: T = Base as any) {
return class extends constructor implements IFlies {
public fly() {
console.log("Hi, I fly!");
}
};
}
function Quacks<T extends Constructor<Base>>(constructor: T = Base as any) {
return class extends constructor implements ICanQuack {
public quack(this: IHasSound, loud: boolean) {
console.log(loud ? this.sound.toUpperCase() : this.sound);
}
};
}
interface IHasSound {
sound: string;
}
interface ICanQuack {
quack(loud: boolean): void;
}
interface IQuacks extends IHasSound, ICanQuack {}
interface IFlies {
fly(): void;
}
class MonsterDuck extends Quacks(Flies()) implements IQuacks, IFlies {
public sound = "quackly!!!";
}
class RubberDuck extends Quacks() implements IQuacks {
public sound = "quack";
}
const monsterDuck = new MonsterDuck();
monsterDuck.quack(true); // "QUACKLY!!!"
monsterDuck.fly(); // "Hi, I fly!"
const rubberDuck = new RubberDuck();
rubberDuck.quack(false); // "quack"
The benefit of using this approach is that you can allow access to certain properties of the owner object in the implementation of the inherited methods. Although a bit better naming could be use, I see this as a very potential solution.
Composition
Composition is instead of mixing the functions into the object, we set what behaviours should be contained in it instead, and then implement these as self-contained libraries inside the object.
interface IQuackBehaviour {
quack(): void;
}
interface IFlyBehaviour {
fly(): void;
}
class NormalQuack implements IQuackBehaviour {
public quack() {
console.log("quack");
}
}
class MonsterQuack implements IQuackBehaviour {
public quack() {
console.log("QUACK!!!");
}
}
class FlyWithWings implements IFlyBehaviour {
public fly() {
console.log("I am flying with wings");
}
}
class CannotFly implements IFlyBehaviour {
public fly() {
console.log("Sorry! Cannot fly");
}
}
interface IDuck {
flyBehaviour: IFlyBehaviour;
quackBehaviour: IQuackBehaviour;
}
class MonsterDuck implements IDuck {
constructor(
public flyBehaviour = new FlyWithWings(),
public quackBehaviour = new MonsterQuack()
) {}
}
class RubberDuck implements IDuck {
constructor(
public flyBehaviour = new CannotFly(),
public quackBehaviour = new NormalQuack()
) {}
}
const monsterDuck = new MonsterDuck();
monsterDuck.quackBehaviour.quack(); // "QUACK!!!"
monsterDuck.flyBehaviour.fly(); // "I am flying with wings"
const rubberDuck = new RubberDuck();
rubberDuck.quackBehaviour.quack(); // "quack"
As you can see, the practical difference is that the composites doesn't know of any properties existing on the object using it. This is probably a good thing, as it conforms to the principle of Composition over Inheritance.
Unfortunately, there is no easy way to do this. There is currently a proposal to allow for the extends keyword to allow you to do this, but it is still being talked about in this GitHub issue.
Your only other option is to use the Mixins functionality available in TypeScript, but the problem with that approach is that you have to re-define each function or method that you want to re-use from the "inherited" classes.
I need to extend the two classes from the same namespace.
for ex:
declare namespace myNameSpace{
class class1{
///some methods will be here
}
class class3 extends class1{
//some method wil be here
}
class class2 extends myNameSpace. class3 {
//some methods will be here
}
export namespace class2 {
//declaration will be here
}
}
i need to extend the 'myNameSpace.class1' class as well as 'class2' namespace.
class newClass extends myNameSpace.class1, myNameSpace.class2 {
constructor() {
super();
}
}
If i call the both the classes, i got an error message
classes can only extend a single class
Is there any other way to fix this issue in typescript.
Is there any other way to fix this issue in typescript.
TypeScript is single inheritance by design.
You can use mixins but you can't override methods (unless you write a custom applyMixins methods)
Using the method:
function applyMixins(derivedCtor: any, baseCtors: any[]) {
baseCtors.forEach(baseCtor => {
Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
derivedCtor.prototype[name] = baseCtor.prototype[name];
});
});
}
You have to implement (on empty way)
class NewClass implements myNameSpace.class1, myNameSpace.class2 {
// empty implementation
public methodFrom1 : ()=>void;
public methodFrom2 : ()=>number;
constructor() {
// no super()
}
}
now use mixing to actually make it multi extend classes:
applyMixins(NewClass, [myNameSpace.class1, myNameSpace.class2]);
and now you can create the class
const foo = new NewClass()
foo.methodFrom1() // actually calls nameSpace.class1.prototype.methodFrom1