Developer Tools

TypeScript 5.5 cut some friction from filter code

1 min read

TypeScript 5.5 made common filter pipelines less noisy through inferred type predicates.

Older versions often needed a helper after mapping optional values:

const scores = studentIds
  .map((id) => scoreByStudent.get(id))
  .filter((score) => score !== undefined)

const average = scores.reduce((sum, score) => sum + score, 0) / scores.length

A reusable predicate worked:

function isDefined<T>(value: T | undefined): value is T {
  return value !== undefined
}

The improvement is not permission to write vague filters. Truthiness can remove valid zeroes:

const scores = [0, 82, 91, undefined].filter((score) => !!score)

Use the condition that expresses the actual boundary:

const scores = [0, 82, 91, undefined].filter(
  (score) => score !== undefined,
)

The compiler can now carry more of the ordinary case without an assertion:

const visibleItems = items
  .map((item) => item.details)
  .filter((details) => details !== undefined)

return visibleItems.map((details) => (
  <DetailCard key={details.id} details={details} />
))

Inferred predicates do not excuse side effects or unclear domain logic inside filters. Keep predicates small and truthful.

The feature is modest. Its value is cumulative: fewer helper functions, fewer assertions, and calmer array pipelines.

Jeremy London

About Jeremy London

Engineering leader and builder in Denver. I write about AI platforms, agents, security, reliability, homelab infrastructure, and the parts of engineering work that have to survive production.