umma.dev

TypeScript 5.5

Inferred Type Predicates

Previously you had to specify if an array was undefined but the new version takes away this complexity.

Now, instead of having MyArray: [] | undefined you can simply have MyArray:[] and it shouldn’t cause anyway issues.

Here’s an example from the docs:

function makeBirdCalls(countries: string[]) {
  // birds: (Bird | undefined)[]
  const birds = countries
    .map((country) => nationalBirds.get(country))
    .filter((bird) => bird !== undefined);

  /* using the birds array would have caused an error here but the new version let's this code pass ok and you shouldn't get an undefined error */
  for (const birds of birds) {
    bird.sing();
  }
}

Why Does This Work?

TypeScript now infers a type predicate for the filter function. As you may be aware, this has been a problem for quite a while, previously the type was inferred to return a boolean but now anything with a signature of type like, x is number or x is NonNullable<T> will now be inferred.

This May Break your Code…

If you’ve inferred a type on filter, for example nulls, it may break the code. The code below from the docs shows you exactly what and how it could be changed.

// previously...
const nums = [1, 2, 3, null, 5].filter((x) => x !== null);
nums.push(null); // version 5.4 fine, 5.5 error

// updated version
const numbers: (number | null)[] = [1, 2, 3, null, 5].filter((x) => x !== null);
nums.push(null);

Set Methods Support (New ECMAScript)

let fruits = new Set(["apples", "bananas", "pears", "oranges"]);
let applesAndBananas = new Set(["apples", "bananas"]);
let applesAndOranges = new Set(["apples", "oranges"]);
let oranges = new Set(["oranges"]);
let emptySet = new Set();

////
// union
////

// Set(4) {'apples', 'bananas', 'pears', 'oranges'}
console.log(fruits.union(oranges));

// Set(3) {'apples', 'bananas', 'oranges'}
console.log(applesAndBananas.union(oranges));

////
// intersection
////

// Set(2) {'apples', 'bananas'}
console.log(fruits.intersection(applesAndBananas));

// Set(0) {}
console.log(applesAndBananas.intersection(oranges));

// Set(1) {'apples'}
console.log(applesAndBananas.intersection(applesAndOranges));

////
// difference
////

// Set(3) {'apples', 'bananas', 'pears'}
console.log(fruits.difference(oranges));

// Set(2) {'pears', 'oranges'}
console.log(fruits.difference(applesAndBananas));

// Set(1) {'bananas'}
console.log(applesAndBananas.difference(applesAndOranges));

////
// symmetricDifference
////

// Set(2) {'bananas', 'oranges'}
console.log(applesAndBananas.symmetricDifference(applesAndOranges)); // no apples

////
// isDisjointFrom
////

// true
console.log(applesAndBananas.isDisjointFrom(oranges));

// false
console.log(applesAndBananas.isDisjointFrom(applesAndOranges));

// true
console.log(fruits.isDisjointFrom(emptySet));

// true
console.log(emptySet.isDisjointFrom(emptySet));

////
// isSubsetOf
////

// true
console.log(applesAndBananas.isSubsetOf(fruits));

// false
console.log(fruits.isSubsetOf(applesAndBananas));

// false
console.log(applesAndBananas.isSubsetOf(oranges));

// true
console.log(fruits.isSubsetOf(fruits));

// true
console.log(emptySet.isSubsetOf(fruits));

////
// isSupersetOf
////

// true
console.log(fruits.isSupersetOf(applesAndBananas));

// false
console.log(applesAndBananas.isSupersetOf(fruits));

// false
console.log(applesAndBananas.isSupersetOf(oranges));

// true
console.log(fruits.isSupersetOf(fruits));

// false
console.log(emptySet.isSupersetOf(fruits));