Typescript 构建器模式来处理带有许多不适应的参数的函数

问题描述 投票:0回答:0

除了this questionthis answer之外,我目前首选的处理带有太多参数的函数的方法是使用context(对象文字作为命名参数)。然而,当使用打字稿时,一切又变得复杂起来。 根据这篇博客,我实现的构建器模式:

class Builder<T extends Record<string, unknown> = {}> {
    private constructor(private readonly object: T) {}

    public add<Obj extends object>(object: Obj): Builder<T & Obj>;
    public add<K extends string, V>(key: K, value: V): Builder<T & { [k in K]: V }>;
    public add(arg1: any, arg2?: any) {
        if (typeof arg1 === 'string') {
            return new Builder(Object.assign(this.object, { [arg1]: arg2 }));
        }
        return new Builder(Object.assign(this.object, arg1));
    }

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

    static create<T extends Record<string, unknown> = {}>(object: T = {} as any): Builder<T> {
        return new Builder(object);
    }
}

用例:

type InferObject<T extends Builder> = T extends Builder<infer Res> ? Res : never;
export type AddField<T extends Builder, U extends object> = Builder<InferObject<T> & U>;

type BaseContext = Builder<{
    a: number;
    b: number;
}>;

// Here I need to pre-define the `SecondContext` type to fulfil the `second` function signature
type SecondContext = AddField<BaseContext, {
    c: number;
}>;

// Here I need to pre-define the `ThirdContext` type to fulfil the `third` function signature
type ThirdContext = AddField<SecondContext, {
    d: number
}>;

first(Builder.create({ a: 1, b: 2 }));

function first(context: BaseContext) {
    const { a, b } = context.build();
    // do sth around a, b
    const newContext = context.add({ c: 3 });
    second(newContext);
}

function second(context: SecondContext) {
    const { a, b, c } = context.build();    
    // do sth around a, b, c
    const newContext = context.add({ d: 4 });
    third(newContext);
}

function third(context: ThirdContext) {
    const { a, b, c, d } = context.build();
    // do sth around a, b, c, d    
}

这就是大惊小怪的地方,我必须预先定义所有的上下文类型来完成函数的签名。使用 javascript 时,我可以毫不费力地将我的新上下文传递给以下函数。

我想知道我是否滥用了构建器模式或者这里有什么解决方法吗? TS游乐场

[已更新]

我同意我的

Builder
实现对于这种情况似乎有点矫枉过正,并且
first
second
third
功能令人困惑,这是一个简化且更现实的示例(游乐场链接)。

type BaseParam = {
    a: number;
    b: number;
};

type SecondParam = BaseParam & { c: number };
type ThirdParam = SecondParam & { d: number };

const someUrl = "";

first({ a: 1, b: 2 });

async function first(firstParam: BaseParam) {
    const { a, b } = firstParam;
    // do some calculation around a, b
    const c = await fetch(someUrl, /** using a, b calc result */).then(res => res.json());
    // addtional logic for c
    second({ a, b, c });
}

async function second(secondParam: SecondParam) {  
    const { a, b, c } = secondParam;
    // do some calculation around a, b, c
    const d = await fetch(someUrl, /** using a, b, c calc result */).then(res => res.json());
    // addtional logic for d
    third({  a, b, c, d });
}

async function third(thirdParam: ThirdParam) {
    const { a, b, c, d } = thirdParam;
    // do some calculation around a, b, c, d
    const e = await fetch(someUrl, /** using a, b, c, d calc result */).then(res => res.json());
    // // addtional logic for e
    // then maybe fourth, fifth and so on...
}

老实说,我对这个解决方案也不满意,这对我来说似乎是一个设计问题,但我找不到更好的解决方案。或者我可能需要将问题标题更改为“如何重构丑陋的嵌套函数”?

javascript typescript builder
© www.soinside.com 2019 - 2024. All rights reserved.