You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为含受保护与可选属性的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 03:59:58