当前位置: 首页 > 知识库问答 >
问题:

在Typescript中扩展生成器

彭涵衍
2023-03-14

是否有可能在这个答案中提供等效的内容,但在TypeScript中?

对 Java 生成器类进行子类化

这是迄今为止我对基类的了解:

export class ProfileBuilder {
    name: string;

    withName(value: string): ProfileBuilder {
        this.name= value;
        return this;
    }

    build(): Profile{
        return new Profile(this);
    }
}

export class Profile {
    private name: string;

    constructor(builder: ProfileBuilder) {
        this.name = builder.Name;
    }
}

和扩展类:

export class CustomerBuilder extends ProfileBuilder  {
    email: string;

    withEmail(value: string): ProfileBuilder {
        this.email = value;
        return this;
    }

    build(): Customer {
        return new Customer(this);
    }
}

export class Customer extends Profile {
    private email: string;

    constructor(builder: CustomerBuilder) {
        super(builder);
        this.email= builder.email;
    }
}

正如另一个线程提到的,由于上下文的变化,我将无法按此顺序构建客户:

let customer: Customer = new CustomerBuilder().withName('John')
                                              .withEmail('john@email.com')
                                              .build();

我目前正在尝试使用泛型来解决此问题,但是在为我的 setter 方法返回 this 指针时遇到问题(类型 this 不能分配给类型 T)。有什么想法吗?

共有3个答案

凤修筠
2023-03-14

在类中,一种称为this的特殊类型动态引用当前类的类型。

--打字稿文档

因此,链式方法的返回类型将始终与您实例化的构建器类型匹配,从而允许完全访问该构建器上可用的所有方法,无论它们是继承的、覆盖的还是在子类中添加的。

js prettyprint-override">// -----------
// Parent Class

class ProfileBuilder {
  name?: string;
  
  // The `this` return type will dynamically match the instance type
  withName(value: string): this {
    this.name = value;
    return this;
  }

  build(): Profile {
    return new Profile(this);
  }
}

class Profile {
  private name: string;

  constructor(builder: ProfileBuilder) {
    this.name = builder.name ?? 'default name';
  }
}


// -----------
// Child class

class CustomerBuilder extends ProfileBuilder {
  email?: string;

  // Return `this` here too to allow further subclassing.
  withEmail(value: string): this {
    this.email = value;
    return this;
  }

  build(): Customer {
    return new Customer(this);
  }
}

class Customer extends Profile {
  private email: string;

  constructor(builder: CustomerBuilder) {
    super(builder);
    this.email = builder.email ?? 'default@email.com';
  }
}



// -----------
// Example Usage

// Notice that the order of the `with` methods no longer matters.

let customer: Customer = new CustomerBuilder()
  .withName('John')
  .withEmail('john@email.com')
  .build();

let customer2: Customer = new CustomerBuilder()
  .withEmail('jane@email.com')
  .withName('Jane')
  .build();

export {};

魏熠彤
2023-03-14

我最近遇到了同样的需求,这是我的解决方案,如果我们创建一个配置文件生成器类,我们可以从我们的客户生成器扩展它,并使用super调用基本生成器。

class ProfileBuilder {
    private name: string;

    constructor() {
        this.name = undefined;
    }

    public withName(name: string) {
        this.name = name;
        return this;
    }

    public build() {
        return {
            name: this.name
        }
    }
}

class CustomerBuilder extends ProfileBuilder {
    private email: string;

    constructor() {
        super();

        this.email = undefined;
    }

    public withEmail(email: string) {
        this.email = email;
        return this;
    }

    public build() {
        const base = super.build();
        return {
            ...base,
            email: this.email
        }
    }
}

现在,您可以根据自己的要求创建一个客户:

const customer = new CustomerBuilder()
    .withName("John")
    .withEmail("john@email.com") 
    .build();
蒲昊苍
2023-03-14

找到了解决方案!在查看了我提到的另一个线程上的不同答案后,我最终创建了一个基本抽象类和构建器,然后为我的每个类/构建器对扩展:

abstract class BaseProfileBuilder<T extends BaseProfile, B extends BaseProfileBuilder<T, B>> {
    protected object: T;
    protected thisPointer: B;

    protected abstract createObject(): T;

    protected abstract getThisPointer(): B;

    constructor() {
        this.object = this.createObject();
        this.thisPointer = this.getThisPointer();
    }

    withName(value: string): B {
        this.object.name = value;
        return this.thisPointer;
    }

    build(): T {
        return this.object;
    }
}

abstract class BaseProfile {
    name: string;
}

class ProfileBuilder extends BaseProfileBuilder<Profile, ProfileBuilder> {
    createObject(): Profile {
        return new Profile();
    }

    getThisPointer(): ProfileBuilder {
        return this;
    }
}

class Profile extends BaseProfile {
}

class CustomerBuilder extends BaseProfileBuilder<Customer, CustomerBuilder>  {
    createObject(): Customer {
        return new Customer();
    }

    getThisPointer(): CustomerBuilder {
        return this;
    }

    withEmail(value: string): CustomerBuilder {
        this.object.email = value;
        return this;
    }
}

class Customer extends BaseProfile {
    email: string;
}


let customer: Customer = new CustomerBuilder().withName('John')
                                              .withEmail('john@email.com')
                                              .build();

console.log(customer);
 类似资料:
  • 目录 1. ext_skel 2. PECL_Gen 3. 小结 毫无疑问你已经注意到,每个php扩展都包含一些非常公共的并且非常单调的结构和文件。当开始一个新扩展开发的时候,如果这些公共的结构已经存在, 我们只用考虑填充功 能代码是很有意义的. 为此, 在php中包含了一个简单但是很有用的shell脚本。

  • 问题内容: 我正在将React.js与TypeScript一起使用。有什么方法可以创建从其他组件继承但具有一些其他道具/状态的React组件? 我想要达到的目标是这样的: 但是,如果我把这个会失败中,我得到一个错误的打字稿(类型的参数是不能分配给类型)。我想这不是TypeScript专用的东西,而是将继承与泛型(?)混合使用的一般限制。是否有任何类型安全的解决方法? 更新 我选择的解决方案(基于D

  • 这个问题已经被问了好几次了,但没有一个答案对我有效。我试图扩展Express请求对象,使其包含一个属性来存储用户对象。我创建了一个声明文件,

  • 所以,我需要在CMS中做一个扩展,称为TYPO3。这里有一些关于这个扩展的信息: “对于新的TYPO3 6.1网站,我们需要一个新闻稿扩展(基于ExtBase/Fluid),该扩展应包含: 标题/说明 目前实际上没有详细视图的设计,所以没有详细视图的链接。所以,现在,请专注于前端列表视图。" 我以前从未使用过这个CMS,所以我读了一下,发现我需要使用扩展生成器来创建这个扩展。所以,我已经下载并安装

  • 我有一个节点。js应用程序,将一些配置信息附加到对象: TypeScript 编译器不喜欢这样,因为 类型没有名为 的对象: TS2339:类型“Global”上不存在属性“myConfig”。 我不想这样做: 我如何扩展< code>Global类型以包含< code>myConfig或者只是告诉TypeScript闭嘴并相信我?我更喜欢第一个。 我不想更改中的声明。我看到了这篇SO帖子,并尝试

  • 问题内容: 我有一个node.js应用程序,该应用程序将一些配置信息附加到该对象: TypeScript编译器不喜欢这样,因为该类型没有名为的对象: TS2339:类型“ Global”上不存在属性“ myConfig”。 我不想这样做: 如何扩展类型以包含或只是告诉TypeScript关闭并信任我?我希望第一个。 我不想更改其中的声明。我看到了这样的帖子,并尝试了这个: 作为扩展现有接口的一种方