typescriptsequelize.jssequelize-typescript

Sequelize TypeScript Error: "Property '[OpTypes.and]' does not exist on type 'WhereAttributeHash<any>'"


I'm trying to dynamically build a WHERE clause using Sequelize in a TypeScript application, but I am encountering a typing error when attempting to use [Op.and] within WhereOptions. Specifically, TypeScript throws the following error:

Property '[Op.and]' does not exist on type 'WhereAttributeHash<any>'

Here is a simplified code example that reproduces the issue:

import { Op, WhereOptions } from 'sequelize';

interface PersonFilters {
    firstName?: string;
    lastName?: string;
    age?: string;
}

export const getPerson = async (filters: PersonFilters): Promise<Person[]> => {
    const whereOptions: WhereOptions = {
        [Op.and]: []
    };

    if (filters.firstName) {
        whereOptions[Op.and].push({ firstName: filters.firstName });
    }

    if (filters.lastName) {
        whereOptions[Op.and].push({ lastName: filters.lastName });
    }

    if (filters.age) {
        whereOptions[Op.and].push({ age: filters.age });
    }

    return await Person.findAll({
        where: whereOptions
    });
}

If I set whereOptions's type to any, the code runs without issues. However, I would like to keep strict type safety wherever possible.

I searched for similar issues online, but most examples I found use JavaScript. I am likely overlooking something.


Solution

  • The simplest way to solve the issue would be to set types explicitly:

    const whereOptions: WhereOptions<Person> = {
        [Op.and]: [] as WhereOptions<Person>[], // Explicitly define Op.and as an array of WhereOptions<Person>
      };
    

    But also, would be worth noting that you can build Op.and conditionally to avoid AND [] clause to appear in your query.

    export const getPerson = async (filters: PersonFilters): Promise<Person[]> => {
        const conditions: WhereOptions<Person>[] = [];
    
        if (filters.firstName) conditions.push({ firstName: filters.firstName });
        if (filters.lastName) conditions.push({ lastName: filters.lastName });
        if (filters.age) conditions.push({ age: filters.age });
    
        const whereOptions: WhereOptions<Person> = conditions.length > 0
            ? { [Op.and]: conditions }
            : {};
    
        return await Person.findAll({
            where: whereOptions,
        });
    };