【问题标题】:What's the type of a mixin classmixin 类的类型是什么
【发布时间】:2018-05-23 17:48:04
【问题描述】:

我无法弄清楚如何在不求助于一些 hack 的情况下获取 typescript mixin 类的类型(如下所示)

type Constructor<T = {}> = new(...args: any[]) => T;

function MyMixin<T extends Constructor>(BaseClass: T) {
  return class extends BaseClass {doY() {}}
}

// Option A: Ugly/wasteful
const MixedA = MyMixin(class {doX() {}});
const dummy = new MixedA();
type MixedA = typeof dummy;

class OtherA {
  field: MixedA = new MixedA();
  a() {this.field.doX(); this.field.doY();}
}

// Option B: Verbose
class Cls {doX() {}}
interface MixinInterface {doY(): void}

const MixedB = MyMixin(Cls);
type MixedB = Cls & MixinInterface;

class OtherB {
  field: MixedB = new MixedB();
  a() {this.field.doX(); this.field.doY();}
}

typescript 不支持诚实的 mixins/traits 让我感到非常难过,但是有没有其他方法可以声明 field 的类型,而无需使用 typeof 实例或不必在接口中重新声明签名(我试过typeof(new MixedBaseA()),但 typeof 不接受任意表达式)?

【问题讨论】:

  • 这与typescriptlang.org/docs/handbook/mixins.html 上的建议不同,例如class SmartObject implements Disposable, Activatable
  • 他们在 2.2 [1] 中引入了对 mixin 类的支持。我认为文档不是最新的 (1: typescriptlang.org/docs/handbook/release-notes/…)
  • @sky 然后不要使用注释。你不需要一个。让编译器推断类型
  • @AluanHaddad 在给出的示例中没问题,但是在更复杂的设置中,我需要在构造函数中实例化字段(因为它取决于某些构造函数参数),而不是指定类型将导致 tsc 推断 any 而不是 mixin 类类型
  • @sky 说得好。但是,如果构造函数参数也被捕获为字段,您可以在字段初始化程序中引用它

标签: typescript


【解决方案1】:

可能不是您想要的,但这里有一个不那么浪费的选择。给定定义:

type Constructor<T = {}> = new(...args: any[]) => T;

function MyMixin<T extends Constructor>(BaseClass: T) {
    return class extends BaseClass {
        doY() { }
    }
}

const MixedA = MyMixin(class { doX() {} });

您可以使用以下方法获取类型:

function getReturnType<R>(fn: (new(...args: any[]) => R)): R {
  return {} as R;
}

const dummy = getReturnType(MixedA);
type MixedAType = typeof dummy;

const mixedA : MixedAType = new MixedA();
mixedA.doX();
mixedA.doY();

Playground

获取任何表达式类型的建议仍在讨论中:https://github.com/Microsoft/TypeScript/issues/6606。这将摆脱虚拟变量和函数。

或者,为了得到一个干净的type MixedAType = MyMixinY &amp; X,你可以选择在mixin中返回正确的构造函数类型:

type Constructor<T = {}> = new(...args: any[]) => T;

interface MyMixinY {
    doY()
} 

function MixinY<T extends Constructor>(BaseClass: T)
    : Constructor<MyMixinY> & T {

    return <any> class Y extends BaseClass implements MyMixinY {
        doY() { 
            console.log("in Y");
        }
    }
}

const MixedA = MixinY(class X {
    doX() {
        console.log("in X");
    }
});

function getReturnType<R>(fn: (new(...args: any[]) => R)): R {
  return {} as R;
}

const dummy = getReturnType(MixedA);
type MixedAType = typeof dummy; // now is `type MixedAType = MyMixinY & X`

const mixedA: MixedAType = new MixedA();
mixedA.doX();
mixedA.doY();

【讨论】:

  • 光滑,谢谢。如果MixedA 有一个沉重的构造函数/实例,那确实会好得多
  • 添加了另一个示例,其中 MixedAType 被解析为 type MixedAType = MyMixinY &amp; X,这应该有助于 IntelliSense。所以应该说MyMixinY.doY() : any而不是(anonymous class)&lt;typeof(anonymous class)&gt;.doY() : any
猜你喜欢
  • 2012-03-16
  • 1970-01-01
  • 2019-08-10
  • 2019-09-02
  • 2016-08-26
  • 1970-01-01
  • 1970-01-01
  • 2023-02-20
  • 1970-01-01
相关资源
最近更新 更多