Javascript 为什么TypeScript无法识别mixin之间共享的属性?

Javascript 为什么TypeScript无法识别mixin之间共享的属性?,javascript,typescript,oop,inheritance,mixins,Javascript,Typescript,Oop,Inheritance,Mixins,我正在尝试在TypeScript中实现mixin 代码如下: type Mixable = new (...args: any[]) => {}; class Base { constructor(protected _a: string, protected _b: string) {} } const A = (Base: Mixable) => class A extends Base { a() { console.log(this._a); re

我正在尝试在TypeScript中实现mixin

代码如下:

type Mixable = new (...args: any[]) => {};

class Base {
  constructor(protected _a: string, protected _b: string) {}
}

const A = (Base: Mixable) => class A extends Base {
  a() {
    console.log(this._a);
    return this;
  }
};

const B = (Base: Mixable) => class B extends Base {
  b() {
    console.log(this._b);
    return this;
  }
};

const C = A(B(Base));

const o = new C("a","b");

o.a().b();
但不幸的是,编译器无法识别mixin、chain方法和发出的错误之间共享的属性


另外,如果您运行此程序,它将成功运行,并生成预期的输出,而不会出现任何JS错误。

为了访问属性
\u a
\u b
,您需要强制应用mixin的类具有这些属性

另外,在带有
保护的
属性的typescript中,混入可能会很棘手,所以我将它们设置为
公共的

interface HasAB {
  _a: string;
  _b: string;
}

type Mixable = new (...args: any[]) => HasAB

class Base {
  constructor(public _a: string, public _b: string) {}
}
interface AB {
  a: string;
  b: string;
}

这就解决了访问属性的问题

编辑:

我一直在玩这个游戏,不幸的是,混入只是为了不适合非公共属性。使用组合类可以访问传入类的受保护属性,但它们会给我们错误TS4094“导出类表达式的属性\u a”可能不是私有的或受保护的。”因为mixin的属性必须是公共的

我没有足够的信心说这是不可能的,但是如果我是你,我会考虑不同的设计模式。您可以将访问器方法
getA()
getB()
添加到类
Base
。或者您可以定义
readonly public
属性
a
b
,这些属性访问底层
私有
属性
\u a
\u b

下面是第二个案例的分解:

我们定义了一个
接口AB
,它具有
public
属性
a
b
。回想一下,typescript接口中的所有属性本质上都是公共的

interface HasAB {
  _a: string;
  _b: string;
}

type Mixable = new (...args: any[]) => HasAB

class Base {
  constructor(public _a: string, public _b: string) {}
}
interface AB {
  a: string;
  b: string;
}
我们声明,如果可以使用关键字
new
创建is,并且所创建的对象具有
a
b
,则认为某个对象是可混合的

type Mixable = new (...args: any[]) => AB;
我们修改
Base
,使其实现
接口AB
,这将使其
可混合。您可以显式地编写
类基类实现AB
,但不必这样做。只要它可以读取属性
a
b
,它就可以分配给
Mixable
。我们使用javascript getter将
a
b
实现为
只读
属性,这些属性将读取
\u a
\u b
的私有值,但不能修改它们

class Base {
  constructor( protected _a: string, protected _b: string) {}

  get a(): string {
    return this._a;
  }

  get b(): string {
    return this._b;
  }
}
现在是我们的混音。我们说要混合的类必须是
Mixable
类型。我们使用泛型
(Mixed:T)
,这样我们就知道返回的类将拥有传入类的所有属性和方法,而不仅仅是
mixeable
中的属性和方法。这解决了链接的问题

请注意,我重命名了您示例中的方法,因为我使用了
a
b
作为属性的名称,所以我不能将它们也用作方法的名称

const A = <T extends Mixable>(Mixed: T) => class A extends Mixed {
  aMethod() {
    console.log(this.a);
    return this;
  }
};

const B = <T extends Mixable>(Mixed: T) => class B extends Mixed {
  bMethod() {
    console.log(this.b);
    return this;
  }
};

谢谢大家的贡献。这给这个问题增加了巨大的价值

在我继续之前,让我解释一下我的初衷以及我的代码引起的误解

我使用mixin的主要目标是分解我的大型类。因为这将应用于不同的类,所以我正在创建一个帮助器模块。为了使示例易于理解,我发布了一个更简单的实现

关于
Base
标识符,我的意思不是
Base
参数指的是基类,而是父类(即扩展的基)。无论如何,为了消除混淆,我将使用标识符
Parent

所以,这里是我提出的,我相信它是非常可扩展的。请忽略这个奇怪的名字
Libbable
(这只是为了说明这个想法)


类型Mixable=new(…args:any[])=>T;
接口libable{
x:字符串;
a():任何;
}
类型Mixin=可混合;
类库{
构造函数(公共x:string){}
a():this{返回this}
}
常量A=(父级:T)=>类扩展父级{
(){
console.log(this.x);
归还这个;
}
};
常量B=(父级:T)=>类扩展父级{
b(){
返回这个.a();
}
};
常数L=A(B(Lib));
常数o=新的L(“x”);
o、 a().b();


因为,目前,TypeScript无法在mixin之间共享非公共属性。我真的很期待能够使用它,否则,强大的访问修饰符在这里就毫无用处了


由于有必要在基类中声明方法以在mixin中使用它们,因此一旦调用mixin的适用类方法,就会调用它们。这不是我想要的。JS允许我们去掉这个,但是TS没有。如果你有更好的想法来实现我想要的,请随意分享。

const a=(Base:Mixable)=>class a扩展了Base
-“Base”与
class Base
没有关系,它只是mixins@AlekseyL上的
Mixable
文档类型的参数
Base
作为参数传递给mixin生成器,
Base
中可用的属性在
a
B
中也可用。请随意查看JS实现。非常感谢您的贡献。但最终基类将具有受保护的属性,并且只要mixin继承了基类,就应该能够访问这些属性,而且它还应该支持方法链接。要么TypeScript还不能实现,要么我找不到解决方法。protected的问题是我们需要TypeScript了解我们的Mixable类必须有属性a和b,并且TypeScript接口成员被认为是公共的。也许有办法解决这个问题,我只是不知道。我知道如果混音是