打字稿-选项对象或生成器

时间:2020-06-12 13:45:07

标签: typescript design-patterns builder

因此,我正在尝试在我阅读的打字稿中实现“选项对象”,以替代Java Builder模式。

我看到我可以使用生成器,但是实现起来似乎比“选项对象”要复杂得多,后者以更少的代码提供了类似的东西。

这是我想要实现的目标:

class OptionsObject {
    private readonly name : string;
    private readonly no? : number;

    constructor(o : OptionsObject){
        this.name = o.name;
        this.no = o.no;
    }

    uradi() : void{
        console.log(`Number is ${this.no} and name is ${this.name}`);
    }
}

const p = new OptionsObject({
    name:"asd",
    no:11
} as unknown as OptionsObject); //works but no type-safety
p.uradi();

//standard java builder
//const p2 = new OptionsObjectBuilder().name("asd").no(11).build();

我只想将所需的属性传递给new OptionsObject。现在就这样-有效,但是我没有类型安全性。我不想引入其他interface,因为那样的话,我将需要重复属性。

有没有更好的方法来实现类型安全,还是有其他类似于生成器的模式适合打字稿?

3 个答案:

答案 0 :(得分:0)

对于Typescript实用程序类型Partial<T>

来说,这可能是一个很好的用例

documentation中的示例

interface Todo {
    title: string;
    description: string;
}

function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {
    return { ...todo, ...fieldsToUpdate };
}

const todo1 = {
    title: 'organize desk',
    description: 'clear clutter',
};

const todo2 = updateTodo(todo1, {
    description: 'throw out trash',
});

答案 1 :(得分:0)

在您的情况下,您要告诉Typescript构造函数接受class<OptionsObject>类型的对象。

OptionsObject不是普通的javascript对象,就像您要传递的对象一样。

关于此:

我不想引入其他接口,因为那样我就需要重复属性。

您实际上并不是在复制属性,而是在定义合同。如果您不熟悉composition设计模式,那么有几本介绍它的书,包括Head First设计模式和Clean Architecture,您都可以在选择的阅读平台上找到它们。

但是要回答您的问题:

实现所需目标的唯一方法是使用接口。我在下面有一个示例,但是从技术上讲,您将没有来实现该接口,并且可以将其用作参数的类型。通过实现接口,私有成员变量必须变为公共,因为接口成员始终是公共的。

interface OptionsObject {
    readonly name: string;
    readonly no?: number;
}

class OptionsObjectImpl implements OptionsObject {
    readonly name: string; // cannot be private due to being part of the interface
    readonly no: number;

    constructor(o : OptionsObject){
        this.name = o.name;
        this.no = o.no;
    }

    uradi() : void{
        console.log(`Number is ${this.no} and name is ${this.name}`);
    }
}

const p = new OptionsObjectImpl({
    name:"asd",
    no:11
}); //works with type-safety

p.uradi();

希望这会有所帮助。

编辑:添加而无需执行。

interface OptionsObjectInterface {
    readonly name: string;
    readonly no?: number;
}

class OptionsObject {
    private readonly name: string; // cannot be private due to being part of the interface
    private readonly no: number;

    constructor(o : OptionsObjectInterface){
        this.name = o.name;
        this.no = o.no;
    }

    uradi() : void{
        console.log(`Number is ${this.no} and name is ${this.name}`);
    }
}

const p = new OptionsObject({
    name:"asd",
    no:11
}); //works with type-safety

p.uradi();

答案 2 :(得分:0)

如果我们看一下 Builder Pattern 的概念,我们会看到几个简单的东西组成的方法:

  • 构建器对象;
  • 'build' 方法,它验证选项并基于它们构建一个新对象;
  • 主要对象类;

因此,TypeScript 方法的所有不同之处在于我们使用 普通 javascript 对象作为构建器对象,因为我们不需要像在爪哇。但是我们仍然需要类型安全,所以我们只需要定义一个构建器对象的类型。

此外,我们将实现我们的“build”方法作为主对象类的静态方法。

这就是我们得到的:

class MyObject {
    private constructor(readonly prop1: string, readonly prop2: number) {
    }

    // an alternative to the 'build' method
    static createInstance(builder: MyObjectBuilder): MyObject {
        // some validation...

        return new MyObject(builder.prop1, builder.prop2);
    }
}

// We make all props optional to allow specify
// them at any moment as if it would be a builder
type MyObjectBuilder = {
    prop1?: string,
    prop2?: number
};

用法:

let builder: MyObjectBuilder = {};

builder.prop1 = 'text';
builder.prop2 = 7;

let myObject = MyObject.createInstance(builder);

当然,在某些情况下,将 builder 直接传递给我们类的公共构造函数就足够了,但它不能完全替代 Builder Pattern,因为它不仅提供了一种将选项传递给我们的方法一个对象构造函数,但也让我们可以完全控制对象的构建(在比对象本身级别更高的级别上)。