Latest Typescript 5.5 Features Every Web Dev Should know

Latest Typescript 5.5 Features Every Web Dev Should know

·

4 min read

INTRODUCTION

Because TypeScript does not employ semantic versioning, like other libraries do, significant new features and unbreakable modifications may be added in any version update. This explains why, despite not being a significant version update according to semantic versioning rules, version 5.5 can have such significant changes. You may read the complete release notes but I'll go over four new features in TypeScript 5.5 that I find most interesting in this article.

💡
I have a comprehensive semantic versioning article that you can read if you're interested in learning more about what it means.

Array Filtering Improvement

If you've ever tried to filter an array in TypeScript to limit the sorts of items allowed, you've most likely discovered that the TypeScript type never changes.

// v5.4
const array = [1, 2, 3, null]

// TypeScript still thinks numbers is (number | null)[]
// This means TypeScript still thinks our numbers array has null values
const numbers = array.filter(item => item != null)

numbers.forEach(number => {
  // TypeScript will error here because it thinks number could be null
  console.log(number + 1)
})

When we look at this code, it is clear that our numbers array no longer contains null values, but TypeScript is not clever enough to recognize this. That was till now. With TypeScript version 5.5, this code now works as expected.

// v5.5
const array = [1, 2, 3, null]

// TypeScript now knows that numbers is number[]
const numbers = array.filter(item => item != null)

numbers.forEach(number => {
  // No errors
  console.log(number + 1)
})

This will also work if we pass another function to our filter function or use more advanced logic.

// v5.5
const people = [{ name: "Kyle", age: 27 }, { name: "John" }]

// TypeScript now knows that peopleWithAge is ({ name: string, age: number })[]
// This means TypeScript knows that peopleWithAge only has objects with an age and name property
const peopleWithAge = people.filter(person => person.age != null)

peopleWithAge.forEach(person => {
  // No errors
  console.log(`${person.name} will be ${person.age + 1} years old next year`)
})

Object Key Inference Improvement

Another issue with TypeScript was that it struggled to infer the type of an object referenced via an index once the index type was narrowed. When written out, this sounds really complicated, so let us look at an example that makes it clear.

// v5.4
function upperCaseKey(obj: Record<string, unknown>, key: string) {
  if (typeof obj[key] === "string") {
    // Error: TypeScript still thinks obj[key] is unknown
    return obj[key].toUpperCase()
  }
}

As you can see in this code, we've restricted the type of obj[key] to a string, but TypeScript isn't clever enough to recognize that this type was narrowed within the if block. This is why version 5.4 generates an error. To get around this, we'd have to define a new variable to contain the limited type which honestly is just extra work.

// v5.4
function upperCaseKey(obj: Record<string, unknown>, key: string) {
  const value = obj[key]
  if (typeof value === "string") {
    // No errors
    return value.toUpperCase()
  }
}

This new code contains no errors, but it is not ideal because we generated a new variable in memory solely to resolve a TypeScript error. This is why, in version 5.5, TypeScript enhanced this behavior and made index-accessed types work without any changes.

// v5.5
function upperCaseKey(obj: Record<string, unknown>, key: string) {
  if (typeof obj[key] === "string") {
    // No errors
    return obj[key].toUpperCase()
  }
}

Regular Expression Checking

In previous versions of TypeScript, the TypeScript type checker ignored any regular expressions in your code. This meant that you may have an invalid regular expression and TypeScript would not detect it. This is no longer the case in TypeScript 5.5, as TypeScript will check your regular expressions and notify you if they include any potential issues.

const regex1 = /extra(parens))?/
// Error: Unexpected ')'. Did you mean to escape it with backslash?

const regex2 = /capture(?<group>.+) \k<namedImport>/
// Error: There is no capturing group named 'namedImport' in this regular expression.

This is only one example of the many potential bugs that TypeScript can now detect using regular expressions.

New Set methods

The last (but not least) update I'd want to discuss is the additional methods that have been added to the Set class. TypeScript 5.5 now supports all of the new Set methods introduced in JavaScript lately which is awesome if you ask me. This applies to all procedures, including intersection, union, and difference.

const set1 = new Set([1, 2, 3])
const set2 = new Set([3, 4, 5])

const intersection = set1.intersection(set2)
const union = set1.union(set2)
const difference = set1.difference(set2)

This is some thoughtful addition because the new Set methods are quite handy, and we can now use them in TypeScript without encountering any type difficulties.

Conclusion

TypeScript 5.5 may appear to be a minor version, but it includes a number of really nice time saving enhancements. The array filtering feature is by far my favorite, and I'm delighted to see it finally implemented. I can't wait to see what TypeScript has planned for us in the future.