这只是ts注释问题,在js运行时中,一切都能按预期进行。
对于多重继承/混合,我们有一个运行时方法,该方法采用类/对象并创建compound(mixed)类。
class A {
a: string
static staticA: string
}
class B {
b: string
static staticB: string
}
class C extends mixin(A, B) {
c: string
static staticC: string
}
因此我们的mixin
方法创建了C
继承的混合类。现在我们有一些注释问题。简单的mixin
声明看起来像这样(实际上,mixin
也接受T1
和T2
的对象,但为简单起见,我将其从代码中删除了):
interface Constructor<T = {}> {
new (...args: any[]): T;
}
declare function mixin<T1 extends Constructor, T2 extends Constructor> (
mix1: T1,
mix2: T2
): new (...args) => (InstanceType<T1> & InstanceType<T2>)
不幸的是,mixin
返回的类型失去了T1
和T2
的静态方法。
C. /* only 'staticC' is present in autocomplete */
let c = new C;
c. /* all - 'a', 'b' and 'c' are present in autocomplete */
我也尝试返回类型T1 & T2
,但在mixin(A, B)
中得到了错误
[ts]基本构造函数必须都具有相同的返回类型。
对此有什么解决办法吗?
感谢@ titian-cernicova-dragomir。我在这里添加了我的最终解决方案,我扩展了注解以支持对象,不仅是类,还希望对某些人有所帮助。
// Extract static methods from a function (constructor)
type Statics<T> = {
[P in keyof T]: T[P];
}
declare function mixin<
T1 extends Constructor | object,
T2 extends Constructor | object,
T3 extends Constructor | object = {},
T4 extends Constructor | object = {},
> (
mix1: T1,
mix2: T2,
mix3?: T3,
mix4?: T4,
):
(T1 extends Constructor ? Statics<T1> : {}) &
(T2 extends Constructor ? Statics<T2> : {}) &
(T3 extends Constructor ? Statics<T3> : {}) &
(T4 extends Constructor ? Statics<T4> : {}) &
(new (...args: T1 extends Constructor ? ConstructorParameters<T1> : never[]) =>
(T1 extends Constructor ? InstanceType<T1> : T1) &
(T2 extends Constructor ? InstanceType<T2> : T2) &
(T3 extends Constructor ? InstanceType<T3> : T3) &
(T4 extends Constructor ? InstanceType<T4> : T4)
);
class A {
a: string
static staticA: string
}
class B {
b: string
static staticB: string
}
const Utils = {
log () {}
}
class C extends mixin(A, B, Utils) {
c: string
static staticC: string
}
C. // has 'staticA', 'staticB', 'staticC'
let c = new C;
c. // has 'a', 'b', 'c', 'log'
我还从第一类的构造函数(如果有)中添加了参数支持。
...args: T1 extends Constructor ? ConstructorParameters<T1> : never[]
。
不幸的是,我找不到使mixin
批注支持任何数量的参数的解决方案,目前我提出了4种,因为它足以满足我的情况。尽管我们的js mixin
可以接受任意数量的类/对象来创建混合类。
答案 0 :(得分:1)
我看不到您的混合机制...但是它看起来像原始版本,而不是更新版本。
下面摘自TypeScript Mixins Part Three的示例表明,使用这种创建混合方法时,静态属性是根据类型和运行时行为来处理的。
type Constructor<T = {}> = new (...args: any[]) => T;
function Flies<TBase extends Constructor>(Base: TBase) {
return class extends Base {
static altitude = 100;
fly() {
console.log('Is it a bird? Is it a plane?');
}
};
}
function Climbs<TBase extends Constructor>(Base: TBase) {
return class extends Base {
static stickyHands = true;
climb() {
console.log('My spider-sense is tingling.');
}
};
}
class Hero {
constructor(private name: string) {
}
}
const HorseFlyWoman = Climbs(Flies(Hero));
const superhero = new HorseFlyWoman('Shelley');
superhero.climb();
superhero.fly();
console.log(HorseFlyWoman.stickyHands);
console.log(HorseFlyWoman.altitude);
这里是转译版本,因此您可以看到输出:
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
}
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
function Flies(Base) {
var _a;
return _a = /** @class */ (function (_super) {
__extends(class_1, _super);
function class_1() {
return _super !== null && _super.apply(this, arguments) || this;
}
class_1.prototype.fly = function () {
console.log('Is it a bird? Is it a plane?');
};
return class_1;
}(Base)),
_a.altitude = 100,
_a;
}
function Climbs(Base) {
var _a;
return _a = /** @class */ (function (_super) {
__extends(class_2, _super);
function class_2() {
return _super !== null && _super.apply(this, arguments) || this;
}
class_2.prototype.climb = function () {
console.log('My spider-sense is tingling.');
};
return class_2;
}(Base)),
_a.stickyHands = true,
_a;
}
var Hero = /** @class */ (function () {
function Hero(name) {
this.name = name;
}
return Hero;
}());
var HorseFlyWoman = Climbs(Flies(Hero));
var superhero = new HorseFlyWoman('Shelley');
superhero.climb();
superhero.fly();
console.log(HorseFlyWoman.stickyHands);
console.log(HorseFlyWoman.altitude);
答案 1 :(得分:1)
您可以按原样保留原始的mixin
函数,而只用T1
和T2
与返回的构造函数相交
class A {
a!: string
static staticA: string
}
class B {
b!: string
static staticB: string
}
class C extends mixin(A, B) {
c!: string
static staticC: string
}
interface Constructor<T = {}> {
new(...args: any[]): T;
}
declare function mixin<T1 extends Constructor, T2 extends Constructor>(
mix1: T1,
mix2: T2
): {
new(...args: any[]): (InstanceType<T1> & InstanceType<T2>)
} & T1 & T2
C.staticA
C.staticB
C.staticC
let c = new C;
c.a
c.b
c.c
您提到您尝试过T1 & T2
的方法的问题是不会更改构造函数以返回(InstanceType<T1> & InstanceType<T2>)
。您必须将此新签名添加到构造函数和原始类中。