Issues with chaining methods of a class to build a string

I’m trying to make a poor man’s query builder to make my life a bit easier, however I’m starting to regret that decision.

The first issue I ran into was in the constructor, for some reason it didn’t like me initializing this.query to an empty string, so I commented it out.

The second problem is that Typescript doesn’t seem to recognize that I can change select with leftJoin. I’m aware it’s not Typescript’s problem, but I’m just trying to figure out what I’m missing here.

Here is what I have:

type TEQueryBuilderSelect = {
    table: string;
    alias: string;
    entity: string;
};
enum EQueryBuilderJoin {
    LEFT = 'left',
    INNER = 'inner',
}
type TQueryBuilderJoinOnConfigType = {
    sourceColumn: string;
    targetColumn: string;
    targetAlias: string;
    operator: '=' | '!=';
};
interface TQueryBuilderJoin {
    sourceAlias: string;
    table: string;
    joinType: EQueryBuilderJoin;
    joinOnConfig: TQueryBuilderJoinOnConfigType;
}
interface TQueryBuilderLeftJoin extends TQueryBuilderJoin {
    joinType: EQueryBuilderJoin.LEFT;
}

class QueryBuilder {
    static query: string;

    constructor() {
        // this.query = ''
    }

    static getQuery(args: string[]) {
        if (!this.query) {
            this.query = '';
        }

        const query = [this.query, ...args].join(' ');
        this.query = query;

        return query;
    }

    static leftJoin({
        table,
        sourceAlias,
        joinType,
        joinOnConfig: { sourceColumn, targetColumn, operator, targetAlias },
    }: TQueryBuilderLeftJoin) {
        return this.getQuery([
            joinType,
            'join',
            table,
            'as',
            sourceAlias,
            'on',
            `${sourceAlias}.${sourceColumn}`,
            operator,
            `${targetAlias}.${targetColumn}`,
        ]);
    }

    static select({ table, alias, entity }: TEQueryBuilderSelect) {
        return this.getQuery(['select', `${alias}.${entity}`, 'from', table, 'as', alias]);
    }
}

const result = QueryBuilder.select({ entity: '*', table: 'user', alias: 'u' }).leftJoin({
    table: 'settings',
    sourceAlias: 's',
    joinType: EQueryBuilderJoin.LEFT,
    joinConfig: {
        sourceColumn: 'user_id',
        operator: '=',
        targetColumn: 'id',
        targetAlias: 'u',
    },
});

console.log('result', result);

The expected result is:

'select * from user as u left join settings as s on s.user_id = u.id'