Javascript scope with Typescript

Typescript has the capability to narrow down the type of a variable and that is handy when we want to validate our javascript code. However, typescript leaves javascript behaviour when it comes to scope.

Let’s consider an array of people with name and age like below:

type Person = { name: string, age: number }
type SearchFilter = { ageFilter?: number }

let myObj: Person[] = []
myObj.push({ name: "Patrick", age: 30 })
myObj.push({ name: "George", age: 18 })

We want to run an search to verify whether the people are all younger than the age filter, but the code below has an error

const arePeopleLessThan = (myObj: Person[], searchFilter: { ageFilter?: number }): boolean => {
  if (searchFilter.ageFilter) {
    return myObj.reduce((value, person) => value &&= person.age < searchFilter.ageFilter, false)
  }

  return false;
}

The snippet below resolves the issue because the scope of the age filter was failing to be propagated to the function that compares the people’s age

const arePeopleLessThan = (myObj: Person[], searchFilter: { ageFilter?: number }): boolean => {
    const ageFilter = searchFilter.ageFilter
  if (ageFilter) {
    return myObj.reduce((value, person) => value &&= person.age < ageFilter, false)
  }

  return false;
}

The test below should pass for both tests

it("Should find not all person are less than 20", () => {
  const result = arePeopleLessThan(myObj, { ageFilter: 20 });

  expect(result).toEqual(false);

  type test = Expect<Equal<typeof result, boolean>>;
});

it("Should find all person are less than 40", () => {
  const result = arePeopleLessThan(myObj, { ageFilter: 40 });

  expect(result).toEqual(true);

  type test = Expect<Equal<typeof result, boolean>>;
});

Conclusion

Typescript and Javascript behave the same way regarding the scope. However, Typescript can mislead us by thinking it can narrow down the variable. We would think the data remains in scope when further functions reuse the variable.. In this example, we can see the narrowing from Typescript does not propagate the scope. Creating a local variable is still a way to resolve the issue