typescript:如何扩展两个类?

IT技术 javascript oop typescript extends
2021-02-16 05:27:36

我想节省我的时间并在扩展 PIXI 类(一个 2d webGl 渲染器库)的类中重用公共代码。

对象接口:

module Game.Core {
    export interface IObject {}

    export interface IManagedObject extends IObject{
        getKeyInManager(key: string): string;
        setKeyInManager(key: string): IObject;
    }
}

我的问题是,里面的代码getKeyInManagersetKeyInManager不会改变,我想重新使用它,而不是复制它,这里是实现:

export class ObjectThatShouldAlsoBeExtended{
    private _keyInManager: string;

    public getKeyInManager(key: string): string{
        return this._keyInManager;
    }

    public setKeyInManager(key: string): DisplayObject{
        this._keyInManager = key;
        return this;
    }
}

我想要做的是通过 a 自动添加Manager.add()管理器中使用的键,以在其 property 中引用对象本身内部的对象_keyInManager

因此,让我们以纹理为例。这是TextureManager

module Game.Managers {
    export class TextureManager extends Game.Managers.Manager {

        public createFromLocalImage(name: string, relativePath: string): Game.Core.Texture{
            return this.add(name, Game.Core.Texture.fromImage("/" + relativePath)).get(name);
        }
    }
}

当我这样做时this.add(),我希望该Game.Managers.Manager add()方法调用一个方法,该方法将存在于Game.Core.Texture.fromImage("/" + relativePath). 这个对象,在这种情况下将是一个Texture

module Game.Core {
    // I must extend PIXI.Texture, but I need to inject the methods in IManagedObject.
    export class Texture extends PIXI.Texture {

    }
}

我知道这IManagedObject是一个接口,不能包含实现,但我不知道写什么来ObjectThatShouldAlsoBeExtended在我的Texture类中注入类。知道SpriteTilingSpriteLayer需要相同的过程

我在这里需要有经验的 TypeScript 反馈/建议,必须有可能做到,但不能通过多个扩展,因为当时只有一个是可能的,我没有找到任何其他解决方案。

6个回答

TypeScript 中有一个鲜为人知的特性,它允许您使用 Mixins 创建可重用的小对象。您可以使用多重继承将它们组合成更大的对象(类不允许多重继承,但 mixin 是允许的 - 这就像具有关联实现的接口)。

有关 TypeScript Mixins 的更多信息

我认为您可以使用这种技术在游戏中的许多类之间共享公共组件,并从游戏中的单个类中重用其中的许多组件:

这是一个快速的 Mixins 演示......首先,你想要混合的口味:

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

class CanSleep {
    sleep() {
        alert('Zzzzzzz.');
    }
}

然后是 Mixin 创建的神奇方法(你只需要在你的程序中的某个地方使用一次......)

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

然后你可以从 mixin 风格创建具有多重继承的类:

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

请注意,此类中没有实际实现 - 足以使其通过“接口”的要求。但是当我们使用这个类时 - 一切正常。

var being = new Being();

// Zzzzzzz...
being.sleep();
这是 TypeScript 手册中的 Mixins 部分(但 Steve 在这个答案和他的链接文章中几乎涵盖了你需要知道的所有内容)typescriptlang.org/Handbook#mixins
2021-04-29 05:27:36
本示例中显示的执行 mixin 的“旧方法”比“新方法”(Typescript 2.2+)更简单。我不知道为什么他们让这变得如此困难。
2021-04-29 05:27:36
原因是“旧方法”无法正确获取类型。
2021-04-29 05:27:36
Typescript 2.2 现在支持Mixin
2021-05-01 05:27:36
@FlavienVolken 你知道为什么微软在他们的手册文档中保留了旧的 mixins 部分吗?顺便说一句,对于像我这样的 TS 初学者来说,发行说明真的很难理解。TS 2.2+ mixins 教程的任何链接?谢谢。
2021-05-13 05:27:36

我建议使用那里描述的新混合方法:https : //blogs.msdn.microsoft.com/typescript/2017/02/22/annoucing-typescript-2-2/

这种方法比 Fenton 描述的“applyMixins”方法更好,因为自动编译器将帮助您并显示来自基类和第二个继承类的所有方法/属性。

可以在TS Playground 站点上检查此方法

这是实现:

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();
这种来自 Typescript 的“新混合方法”看起来像是事后的想法。作为开发人员,我只想能够说“我希望这个类继承 ClassA 和 ClassB”或“我希望这个类是 ClassA 和 ClassB 的混合”,我想用我能记住的清晰语法来表达在 6 个月内,不是那种笨手笨脚的笨蛋。如果这是 TS 编译器可能性的技术限制,那就这样吧,但这不是解决方案。
2021-04-15 05:27:36
这里的问题是 TS 仍然对修改后的类一无所知。我可以输入secondInheritanceObj.some()但没有收到警告消息。
2021-04-20 05:27:36
这种 mixins 实现的要点是,两个类的所有方法和属性都将显示在自动完成 IDE 帮助中。如果需要,您可以定义第二个类并使用 Fenton 建议的方法,但在这种情况下,IDE 自动完成将不起作用。{new (...args)} - 这段代码描述了一个应该是一个类的对象(你可以在手册中阅读更多关于 TS 接口的信息:typescriptlang.org/docs/handbook/interfaces.html
2021-04-23 05:27:36
如何检查 Mixed 类是否遵守接口?
2021-04-23 05:27:36
SecondInheritanceClass不是故意的定义还是我失去了一些东西?将此代码加载到 TS 游乐场时,它会显示expecting =>. 最后,您能否准确地分解addSecondInheritance函数中发生的事情,例如 的目的是new (...args)什么?
2021-05-03 05:27:36

TypeScript 支持装饰器,使用该特性加上一个名为typescript-mix的小库,你可以使用 mixins 来实现多重继承,只需几行

// 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;
}

我找到了一个最新且无与伦比的解决方案:https : //www.npmjs.com/package/ts-mixer

不客气 :)

我正在使用 nestjs 并且它具有开箱即用的 swagger 工作,nestjs/swagger 有自己的装饰器,例如@ApiProperty和其他。并且似乎这些装饰器不会被继承,如果我尝试将它们包装起来,则会@decorator出现循环依赖错误。也许有人也遇到了那个错误并想出了一些解决方案?我将不胜感激。
2021-04-16 05:27:36
在尝试使多重继承与记录的 mixins 模式(显然是旧版本)、未记录的 mixins 模式(非常嘈杂/样板)一起工作后,以及制作基于自定义装饰器的库,测试多个可用库等。 . 我必须说 ts-mixer 是最容易使用的,并且(至少对于我的用例)它是最接近解决方案的,没有任何麻烦。这应该是公认的答案。
2021-05-03 05:27:36
最佳答案 !!!
2021-05-09 05:27:36

不幸的是,typescript不支持多重继承。因此,没有完全微不足道的答案,您可能必须重组您的程序

这里有一些建议:

  • 如果这个额外的类包含许多子类共享的行为,那么将它插入到类层次结构的顶部某处是有意义的。也许你可以从这个类中派生出 Sprite、Texture、Layer 等通用超类?如果您能在类型层次结构中找到一个好位置,这将是一个不错的选择。但我不建议在随机点插入这个类。继承表达了“是-关系”,例如狗是动物,纹理是此类的一个实例。您必须问自己,这是否真的模拟了代码中对象之间的关系。一棵逻辑继承树很有value

  • 如果附加类在逻辑上不适合类型层次结构,则可以使用聚合。这意味着您将此类类型的实例变量添加到 Sprite、Texture、Layer 的公共超类中,然后您可以在所有子类中使用其 getter/setter 访问该变量。这模拟了“具有 - 关系”。

  • 您还可以将您的类转换为接口。然后,您可以使用所有类扩展接口,但必须在每个类中正确实现方法。这意味着一些代码冗余,但在这种情况下并不多。

你必须自己决定你最喜欢哪种方法。我个人建议将类转换为接口。

一个提示:Typescript 提供了属性,这些属性是 getter 和 setter 的语法糖。你可能想看看这个:http : //blogs.microsoft.co.il/gilf/2013/01/22/creating-properties-in-typescript/

如果所有这些类都扩展了 PIXI,那么只需让 ObjectThatShouldAlsoBeExtended 类扩展 PIXI 并从中派生出 Texture、Sprite、... 类。这就是我在类型层次结构中插入类的意思
2021-05-01 05:27:36
PIXI 本身不是一个类,它是一个module,它不能被扩展,但你是对的,如果是的话,那将是一个可行的选择!
2021-05-01 05:27:36
确实很有趣的链接,但我在这里没有看到任何解决问题的用例。
2021-05-02 05:27:36
有趣的。1)我不能这样做,仅仅因为我扩展了PIXI并且我无法更改库以在其上添加另一个类。2)这是我可以使用的可能解决方案之一,但如果可能的话,我宁愿避免它。3)我绝对不想复制那个代码,现在可能很简单,但接下来会发生什么?我只在这个程序上工作了一天,稍后我会添加更多,这对我来说不是一个好的解决方案。我会看看提示,谢谢你的详细回答。
2021-05-10 05:27:36
那么每个类都从 PIXI module扩展了另一个类?那么你是对的,你不能将 ObjectThatShouldAlso 类插入到类型层次结构中。那是不可能的。您仍然可以选择 has-a 关系或接口。由于您想描述所有类共享的常见行为,我建议使用接口。这是最干净的设计,即使代码是重复的。
2021-05-12 05:27:36