WBT
WBT

Reputation: 2465

Typescript canonical builder pattern?

I have a JavaScript codebase with several examples of the following (playground link here):

interface ComplexObject {
    field1: string;
    field2: boolean;
    field3: number;
}
declare function getField1(): Promise<string>;
declare function getField2(): Promise<boolean>;
declare function getField3(): Promise<number>;
const promiseBuilder = function() : Promise<ComplexObject> {
    //Not using Partial here results in a ts(2739) error that
    //field1, field2, field3 are missing from type '{}'.
    const result: Partial<ComplexObject> = {}
    return new Promise(function (resolve, reject) {
        getField1().then(function(field1){
            result.field1 = field1;
            return getField2();
        }).then(function(field2){
            result.field2 = field2;
            if(field2) {
                return getField3();
            } else {
                return Promise.resolve(0);
            }
        }).then(function(field3){
            result.field3 = field3;
            //result now has all the fields, but there's an error:
            //Partial<ComplexObject>' is not assignable to 'ComplexObject'.
            resolve(result); 
        }).catch(function(err) {
            reject(err);
        });
    })
}

Without type annotations, this works just fine in JavaScript, but in TypeScript it has the errors indicated.

What is the canonical way to do something like this in TypeScript?

Upvotes: 1

Views: 262

Answers (1)

WBT
WBT

Reputation: 2465

The closest found so far requires converting to the async style, using local consts to hold the values temporarily, and assembling the entire object at once, like this (playground link here):

const asyncBuilder = async function() : Promise<ComplexObject> {
    const field1 = await getField1();
    const field2 = await getField2();
    let field3 = 0;
    if(field2) {
        field3 = await getField3();
    }
    return { field1, field2, field3 };
}

However, that means a lot of rewriting what was previously valid code, so if there's a way to do it with less code rewriting, that would be good to know about!

Upvotes: 1

Related Questions