Home > database >  TypeScript - How can i deal with multiple IFs
TypeScript - How can i deal with multiple IFs

Time:05-12

I was trying to do a "multiple filter" in TS, So...

If i send nothing -> it returns all products normally;

But if i send some params -> it returns products filtered by the params.

(I used colors just for the example)

async load(params: params): LoadProducts.Result => {
  const products = [];

  if (params) {
    if (params.red != undefined) // products.push( ...load.redProducts() );
    if (params.blue != undefined) // products.push( ...load.blueProducts() );
    if (params.green != undefined) // products.push( ...load.greenProducts() );
    if (params.yellow != undefined) // products.push( ...load.yellowProducts() );
  } else {
    // products.push( ...load.products() );
  }

  return products;
}

Type of request:

type params = {
  filter?: {
    red?:  boolean;
    blue?: boolean;
    green?: boolean;
    yellow?: boolean;
  };
};

Example of request:

{
  "filter": {
    "red": true,
    "blue": true
  }
}

How can I deal with the multiple IFs to verify the params, because each has its own function to load and I want to add more filters.

CodePudding user response:

You have not included a minimal, reproducible example, but based on what you have shown, you can use a (map-like) array of tuples and iterate over it:

const colorFns = [
  ['red', load.redProducts.bind(load)],
  ['blue', load.blueProducts.bind(load)],
  // etc...
] as const;

async load(params: params): LoadProducts.Result => {
  const products = [];

  if (params) {
    for (const [color, fn] of colorFns) {
      if (params[color] != undefined) products.push(...fn());
    }
  } else {
    // products.push( ...load.products() );
  }

  return products;
}

CodePudding user response:

If there are lots of filters, the primary thing is probably to avoid repeating yourself. So I would make the functions that do the loading drive the process: You define an object with those functions as const, then derive your possible filters from that. Here's an example (see inline comments):

// Placeholder for your product type
type Product = {
    name: string;
    type: string;
};

// The functions that do the loading of individual types
const loaders = {
    async red() {
        return [{ type: "red", name: "Red 1" }];
    },
    async blue() {
        return [{ type: "blue", name: "Blue 1" }];
    },
    async green() {
        return [{ type: "green", name: "Green 1" }];
    },
    async yellow() {
        return [
            { type: "yellow", name: "Yellow 1" },
            { type: "yellow", name: "Yellow 2" },
        ];
    },
} as const;

// A function that loads everything
const loadAll = async () => {
    const allLoaders = Object.values(loaders);
    return (
        await Promise.all(allLoaders.map(loader => loader()))
    ).flat();
};

// The types of filters we might have
type FilterType = keyof typeof loaders;

// The params type
type ParamsFilters = {
    [Key in FilterType]?: boolean;
};
type Params = {
    filter?: ParamsFilters;
};

// A function that asserts a string key is a valid key for `loaders`
function assertIsLoaderKey(key: string): asserts key is keyof typeof loaders {
    if (!(key in loaders)) {
        throw new Error(`Expected key for 'loaders', got "${key}"`);
    }
}

// The class this is apparently in
class Example {
    async load(params: Params): Promise<Product[]> {
        let products: Product[];

        // If we have filters...
        if (params.filter) {
            // ...run them
            products = (
                await Promise.all(
                    Object.entries(params.filter)
                        .filter(([key, flag]) => flag)
                        .map(([key]) => {
                            assertIsLoaderKey(key);
                            return loaders[key]();
                        })
                )
            ).flat();
        } else {
            // No filters, load everything
            products = await loadAll();
        }

        return products;
    }
}

// Example usage
const e = new Example();
e.load({
    filter: {
        red: true,
        blue: true,
    },
});

Playground link

(That uses the relatively-new flat method. It's supported by even vaguely recent versions of modern browsers, but may need polyfilling for old ones.)

  • Related