Typescript: How to extend two classes?

前端 未结 9 1059
猫巷女王i
猫巷女王i 2020-11-29 22:38

I want to save my time and to reuse common code across classes which extends PIXI classes (a 2d webGl renderer library).

Object Interfaces:

相关标签:
9条回答
  • 2020-11-29 23:13

    I would suggest using the new mixins approach described there: https://blogs.msdn.microsoft.com/typescript/2017/02/22/announcing-typescript-2-2/

    This approach is better, than the "applyMixins" approach described by Fenton, because the autocompiler would help you and show all the methods / properties from the both base and 2nd inheritance classes.

    This approach might be checked on the TS Playground site.

    Here is the implementation:

    class MainClass {
        testMainClass() {
            alert("testMainClass");
        }
    }
    
    const addSecondInheritance = (BaseClass: { new(...args) }) => {
        return class extends BaseClass {
            testSecondInheritance() {
                alert("testSecondInheritance");
            }
        }
    }
    
    // Prepare the new class, which "inherits" 2 classes (MainClass and the cass declared in the addSecondInheritance method)
    const SecondInheritanceClass = addSecondInheritance(MainClass);
    // Create object from the new prepared class
    const secondInheritanceObj = new SecondInheritanceClass();
    secondInheritanceObj.testMainClass();
    secondInheritanceObj.testSecondInheritance();
    
    0 讨论(0)
  • 2020-11-29 23:13

    Unfortunately typescript does not support multiple inheritance. Therefore there is no completely trivial answer, you will probably have to restructure your program

    Here are a few suggestions:

    • If this additional class contains behaviour that many of your subclasses share, it makes sense to insert it into the class hierarchy, somewhere at the top. Maybe you could derive the common superclass of Sprite, Texture, Layer, ... from this class ? This would be a good choice, if you can find a good spot in the type hirarchy. But I would not recommend to just insert this class at a random point. Inheritance expresses an "Is a - relationship" e.g. a dog is an animal, a texture is an instance of this class. You would have to ask yourself, if this really models the relationship between the objects in your code. A logical inheritance tree is very valuable

    • If the additional class does not fit logically into the type hierarchy, you could use aggregation. That means that you add an instance variable of the type of this class to a common superclass of Sprite, Texture, Layer, ... Then you can access the variable with its getter/setter in all subclasses. This models a "Has a - relationship".

    • You could also convert your class into an interface. Then you could extend the interface with all your classes but would have to implement the methods correctly in each class. This means some code redundancy but in this case not much.

    You have to decide for yourself which approach you like best. Personally I would recommend to convert the class to an interface.

    One tip: Typescript offers properties, which are syntactic sugar for getters and setters. You might want to take a look at this: http://blogs.microsoft.co.il/gilf/2013/01/22/creating-properties-in-typescript/

    0 讨论(0)
  • 2020-11-29 23:13

    TypeScript supports decorators, and using that feature plus a little library called typescript-mix you can use mixins to have multiple inheritance with just a couple of lines

    // The following line is only for intellisense to work
    interface Shopperholic extends Buyer, Transportable {}
    
    class Shopperholic {
      // The following line is where we "extend" from other 2 classes
      @use( Buyer, Transportable ) this 
      price = 2000;
    }
    
    0 讨论(0)
  • 2020-11-29 23:19

    There is a little known feature in TypeScript that allows you to use Mixins to create re-usable small objects. You can compose these into larger objects using multiple inheritance (multiple inheritance is not allowed for classes, but it is allowed for mixins - which are like interfaces with an associated implenentation).

    More information on TypeScript Mixins

    I think you could use this technique to share common components between many classes in your game and to re-use many of these components from a single class in your game:

    Here is a quick Mixins demo... first, the flavours that you want to mix:

    class CanEat {
        public eat() {
            alert('Munch Munch.');
        }
    }
    
    class CanSleep {
        sleep() {
            alert('Zzzzzzz.');
        }
    }
    

    Then the magic method for Mixin creation (you only need this once somewhere in your program...)

    function applyMixins(derivedCtor: any, baseCtors: any[]) {
        baseCtors.forEach(baseCtor => {
            Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
                 if (name !== 'constructor') {
                    derivedCtor.prototype[name] = baseCtor.prototype[name];
                }
            });
        }); 
    }
    

    And then you can create classes with multiple inheritance from mixin flavours:

    class Being implements CanEat, CanSleep {
            eat: () => void;
            sleep: () => void;
    }
    applyMixins (Being, [CanEat, CanSleep]);
    

    Note that there is no actual implementation in this class - just enough to make it pass the requirements of the "interfaces". But when we use this class - it all works.

    var being = new Being();
    
    // Zzzzzzz...
    being.sleep();
    
    0 讨论(0)
  • 2020-11-29 23:21

    I found an up-to-date & unparalleled solution: https://www.npmjs.com/package/ts-mixer

    0 讨论(0)
  • 2020-11-29 23:23

    I think there is a much better approach, that allows for solid type-safety and scalability.

    First declare interfaces that you want to implement on your target class:

    interface IBar {
      doBarThings(): void;
    }
    
    interface IBazz {
      doBazzThings(): void;
    }
    
    class Foo implements IBar, IBazz {}
    

    Now we have to add the implementation to the Foo class. We can use class mixins that also implements these interfaces:

    class Base {}
    
    type Constructor<I = Base> = new (...args: any[]) => I;
    
    function Bar<T extends Constructor>(constructor: T = Base as any) {
      return class extends constructor implements IBar {
        public doBarThings() {
          console.log("Do bar!");
        }
      };
    }
    
    function Bazz<T extends Constructor>(constructor: T = Base as any) {
      return class extends constructor implements IBazz {
        public doBazzThings() {
          console.log("Do bazz!");
        }
      };
    }
    

    Extend the Foo class with the class mixins:

    class Foo extends Bar(Bazz()) implements IBar, IBazz {
      public doBarThings() {
        super.doBarThings();
        console.log("Override mixin");
      }
    }
    
    const foo = new Foo();
    foo.doBazzThings(); // Do bazz!
    foo.doBarThings(); // Do bar! // Override mixin
    
    0 讨论(0)
提交回复
热议问题