The Typescript feature we all wanted

The Typescript feature we all wanted

TLDR: Inferred Type Predicates are now available in Typescript 5.5 Beta. In this article, I’ll explain the much-awaited feature and how it’ll help you write more type-safe code.


Introduction

For the most part, Typescript’s control flow analysis does an impressive job of monitoring how the type of a variable changes as it moves through your code.

For example, consider the trivial function that receives either a string or number below:

function echo (val: string| number) {
  if (typeof val === 'string') {
    console.log(`STRING: ${val}`)
    return 
  }

  console.log(val)
}

In this basic example, Typescript can conveniently tell that the variable on line 3 is of type string and the variable on line 7 of type number.

Correct string type inference
Correct number type inference

The reason this is important is that Typescript can spot bugs based on this inferred type, i.e., if we used a wrong string method in line 7, we’d get an error.

This is wonderful.

Let’s now consider a case where Typescript has historically failed.

What the TS??

Consider this perfectly written code:

const values = ["Hello", "World", null, undefined, "Hooray"]

const filteredValues = values.filter((v) => typeof v === 'string')

From a developer’s perspective, this reads nicely.

  • We have a list of values containing either strings or null and undefined
  • We filter out null and undefined so we can work with the remaining string values

However, Typescript is confused.

Typescript error: 'v' is possibly 'null' or 'undefined'

The inferred type of filteredValues is still (string | null | undefined)[] even though we explicitly filtered null and undefined

If you’ve battled this behaviour in the past, you’re not alone.

While there are workarounds to this, from a Typescript control flow analysis perspective, this is code that should simply work out of the box.

Inferred Type Predicates

When I spoke about workarounds, one way to fix this would be to write a type predicate.

A type predicate is really just a function that returns a boolean and is used to narrow down types.

OK, back to the subject of discussion. Why should we need workarounds in the first place?

Well, there’s good news. From Typescript 5.5 Beta, Typescript will now infer type predicates out of the box!

In practical terms, this means the code we wrote earlier now works out of the box. No workarounds, no hacks, no nothing.

Inferred type predicates at work 🎉

No errors!

Conclusion

This seemingly simple change has been seven years in the making. Yes, seven — well, since the initial issue was open.

Typescript 5.5 beta ships with plenty of changes, but none excites me as much as the humble inferred type predicates. Every so often, it’s the simple things that make a difference. At least in my case.


=============== SHAMELESS PLUG ⬇️   ===============

I’m launching a passion project soon and would appreciate your genuine feedback and support. Please hit «notify me» here: https://www.producthunt.com/products/bestregards

===============   ===============   ===============