为含受保护与可选属性的Mixin编写重载签名及问题求助
TypeScript Mixin 问题修复方案
我有一个返回抽象类的Mixin,包含若干方法、属性及可选属性,代码如下:
type AbstractConstructor<T = any> = abstract new (...args: any[]) => T interface IMyMixin { someProp: PropType; optionalProp?: OptionalType; mustImplement(): void; availableMethod(): void; } type IMyMixinWithOptional = IMyMixin & {optionalProp: OptionalType;} export function MixItIn<T extends AbstractConstructor>( base:T , withOptional: true ): AbstractConstructor<IMyMixinWithOptional> export function MixItIn<T extends AbstractConstructor>( base: T, withOptional?: boolean ): AbstractConstructor<IMyMixin> export function MixItIn<T extends AbstractConstructor>( base: T, withOptional?: boolean ) { abstract class MyMixin extends base implements IMyMixin { someProp = new PropType(); optionalProp = withOptional ? new OptionalType() : undefined; abstract mustImplement(): void; availableMethod() { // does stuff } } return MyMixin; } export function MyConvenientMixin(withOptional: true): AbstractConstructor<IMyMixinWithOptional> export function MyConvenientMixin(withOptional?: boolean): AbstractConstructor<IMyMixin> export function MyConvenientMixin(withOptional?: boolean): AbstractConstructor<IMyMixin> { return MixItIn(class {}, withOptional) }
需求:重载签名需明确告知调用者——当传入true调用Mixin或便捷方法时,必然会获得该可选属性。
当前存在两个问题:
IMyMixin的部分属性实际应为protected,子类应知晓并可使用,但接口无法声明受保护属性;尝试改用抽象类却出现实现错误。- 类似
class MyClass extends MixItIn(SomeOtherClass) { }的类无法感知自身继承了SomeOtherClass的方法。
问题1:protected成员的契约定义
接口无法声明protected成员,改用抽象类定义Mixin契约即可解决:
// 用抽象类替代接口,支持protected成员定义 abstract class MyMixinContract { protected someProp: PropType; protected optionalProp?: OptionalType; abstract mustImplement(): void; abstract availableMethod(): void; } // 针对可选属性必存在的场景扩展契约 abstract class MyMixinContractWithOptional extends MyMixinContract { protected optionalProp: OptionalType; }
修改Mixin函数实现,让返回的抽象类同时继承基类和契约类,并通过类型断言确保重载返回类型正确:
export function MixItIn<T extends AbstractConstructor>( base: T, withOptional: true ): AbstractConstructor<InstanceType<T> & MyMixinContractWithOptional> export function MixItIn<T extends AbstractConstructor>( base: T, withOptional?: boolean ): AbstractConstructor<InstanceType<T> & MyMixinContract> export function MixItIn<T extends AbstractConstructor>( base: T, withOptional?: boolean ) { abstract class MyMixin extends base implements MyMixinContract { protected someProp = new PropType(); protected optionalProp = withOptional ? new OptionalType() : undefined; abstract mustImplement(): void; availableMethod() { // does stuff } } return MyMixin as typeof MyMixin & ( withOptional extends true ? AbstractConstructor<InstanceType<T> & MyMixinContractWithOptional> : AbstractConstructor<InstanceType<T> & MyMixinContract> ); }
问题2:继承基类方法的类型感知
原返回类型仅包含Mixin接口,未合并基类类型。通过将InstanceType<T>(基类实例类型)与Mixin契约交叉,子类就能正确感知基类的所有成员。调整后的重载返回类型直接合并了两者,解决类型丢失问题。
便捷方法同步调整
对应修改MyConvenientMixin的返回类型,确保类型一致性:
export function MyConvenientMixin(withOptional: true): AbstractConstructor<MyMixinContractWithOptional> export function MyConvenientMixin(withOptional?: boolean): AbstractConstructor<MyMixinContract> export function MyConvenientMixin(withOptional?: boolean) { return MixItIn(class {}, withOptional) as typeof MixItIn extends ( base: any, opt: infer O ) => infer R ? R : never; }
内容的提问来源于stack exchange,提问作者bryan60
相关产品推荐
相关产品推荐

