TypeScript 允许mixin构造函数在剩余参数之前有参数,

snvhrwxg  于 2个月前  发布在  TypeScript
关注(0)|答案(3)|浏览(35)

搜索词

mixin,构造函数参数

建议

允许mixin构造函数在剩余参数之前有参数,并推断mixin参数之间的组合。

用例

以下js代码是完全有效的且功能性的。然而,由于实际的mixin构造函数约束,我们无法在Typescript中重现此代码。

const mixin1 = (base) => class Mixin1 extends base {
    constructor(m1v1, m1v2, ...args) {
        super(...args);
        this.m1v1 = m1v1;
        this.m1v2 = m1v2;
    }
};
const mixin2 = (base) => class Mixin2 extends base {
    constructor(m2v1, m2v2, ...args) {
        super(...args);
        this.m2v1 = m2v1;
        this.m2v2 = m2v2;
    }
};
class Base {
    constructor(v1, v2) {
        this.v1 = v1;
        this.v2 = v2;
    }
}
class C1 extends mixin1(Base) {
}
class C2 extends mixin2(Base) {
}
class C3 extends mixin2(mixin1(Base)) {
}
console.log(new C1("m1v1", true, 1, {}));
console.log(new C2(false, 2, 1, {}));
console.log(new C3(false, 2, "m1v1", true, 1, {}));

示例

在ts中使用构造函数推断,相同的代码应该可以正常工作。

type Constructor = new (...args: any[]) => object;

const mixin1 = <T extends Constructor>(base: T) =>
    class Mixin1 extends base {
        m1v1: string;
        m1v2: boolean;

        constructor(m1v1: string, m1v2: boolean, ...args: any[]) {
            super(...args);

            this.m1v1 = m1v1;
            this.m1v2 = m1v2;
        }
    }

const mixin2 = <T extends Constructor>(base: T) =>
    class Mixin2 extends base {
        m2v1: boolean;
        m2v2: number;

        constructor(m2v1: boolean, m2v2: number, ...args: any[]) {
            super(...args);

            this.m2v1 = m2v1;
            this.m2v2 = m2v2;
        }
    }

class Base {
    v1: number;
    v2: object;

    constructor(v1: number, v2: object) {
        this.v1 = v1;
        this.v2 = v2;
    }
}

class C1 extends mixin1(Base) {
}

class C2 extends mixin2(Base) {
}

class C3 extends mixin2(mixin1(Base)) {
}

console.log(new C1("m1v1", true, 1, { })); // infer mixin1 and Base parameters: [string, boolean, number, object]
console.log(new C2(false, 2, 1, { })); // infer mixin2 and Base parameters: [boolean, number, number, object]
console.log(new C3(false, 2, "m1v1", true, 1, { })); // infer mixin2, mixin1 and Base parameters: [boolean, number, string, boolean, number, object]

检查清单

我的建议满足以下准则:

  • 这不会对现有的TypeScript/JavaScript代码造成破坏性更改
  • 这不会改变现有JavaScript代码的运行时行为
  • 这可以在不根据表达式的类型发出不同的JS的情况下实现
  • 这不是一个运行时特性(例如库功能,带有JavaScript输出的非ECMAScript语法等)
  • 这个特性将与TypeScript's Design Goals的其他部分保持一致。
x4shl7ld

x4shl7ld1#

编辑:也许需要更多的解释。
让我们考虑以下一组类,如下所示的“代码示例1”部分。
有3个持有者类,分别用于存储字符串、数字和Map。它们工作顺畅,如我们所见,派生类构造函数将子集或参数传递给每个派生类,这些选项对象是基类成员的超集。如果我们想要一个能够保留名称和标签的对象,那么我们必须从头开始实现,就像在“代码示例2”部分中那样。使用mixins来实现这种临时组合会很方便。让我们将INeedCount和INeedTags作为mixins并像在“代码示例3”部分中那样组合它们。
使用mixins轻松地通过具有多个参数或选项的多种构造函数扩展现有类,这将是非常棒的!

gg0vcinb

gg0vcinb2#

如果我理解正确的话,为了使这种类型的组合成为可能,mixin也应该知道基类的参数。是否可以通过泛型约束来实现。

const INeedTagsMixin = <T extends new (options: INeedNameAndTagsOptions) => any>(base: T) =>
  class INeedTagsMixin extends base {
    tags: Map<string, string>;
    constructor(options: INeedNameAndTagsOptions) {
      super(options);
      this.tags = new Map(options.tags);
    }
}

这将是一个有趣的补充。

5us2dqdw

5us2dqdw3#

并非如此。我希望有选项来指定更严格的构造函数,即"...args: any[]"。你示例中的mixin有两个泛型参数。混合类的构造函数将是所需选项属性的交集加上泛型TOptions。
使用多个mixin的 Package 类看起来像洋葱,每一层消耗一个"& TOptions",并将其余部分传递下去。通常,你会用args皮肤传入的选项,最终的构造函数将获得定义的类型。我希望这相当清楚我的意思——否则我可以提供更详细的示例。

相关问题