Search code examples
javascriptarraystypescriptindexofoptional-chaining

Optional chaining in combination with toLowerCase and indexOf during array map


For a autocomplete input I search in project properties during typing. Now I want to improve this code

filterProjects(value: string) {
  return this.projects.filter(
    project =>
      project.key.toLowerCase().indexOf(value.toLowerCase().trim()) >=
        0 ||
      project.name.toLowerCase().indexOf(value.toLowerCase().trim()) >=
        0 ||
      project.description?.toLowerCase().indexOf(value.toLowerCase().trim()) >=
        0
  );
}

with this:

filterProjects(value: string) {
  return this.projects.filter(project =>
    [project.key, project.name, project.description].map(
      str => str?.toLowerCase().indexOf(value.toLowerCase().trim()) >= 0
    )
  );
}

I use the optional chaining because description can be null or undefined.

But it doesn't work, meaning the function always returns the array unmodified. Also, when the value is found in the description of one item, the array doesn't get filtered to only this item.

What could be the solution except using "old" checks like if (str !== undefined) and such?


Solution

  • That map returns an array of booleans, which is always truthy no matter what, so it's not the predicate you are looking for. You need Array.some (also in lodash/underscore/ramda, if you plan to target old browsers). Let me tweak also the inner predicate a little bit:

    filterProjects(value: string) {
      return this.projects.filter(project =>
        [project.key, project.name, project.description].some(str =>
          str ? str.toLowerCase().includes(value.toLowerCase().trim()) : false
        )
      );
    }