How To Filter Nullable Values From An Array Using TypeScript
May 15, 2022 - 5 minutes
If you’ve dealt with any type of complex data in JavaScript development, it’s almost guaranteed that you’ve used the functional Array methods. These methods are shorter and the more functional alternatives to the traditional implementation, often resolving around using a for-loop and populating an array conditionally.
Using these methods in the correct circumstances and in the appropriate environment can significantly improve the quality and readability of your code. This is especially the case when they’re combined with TypeScript. But while TypeScript excellently supports the Array map
function out-of-the-box, the same can’t be said about the Array filter
function.
In particular, we’ll be looking at filtering out nullable values from such an array. From the perspective of the developer, TypeScript doesn’t always correctly pick up on the typing when filtering out nullable values using the filter
function. Even though using operators like !!
or the Boolean
constructor guarantees us to have no nullable values anymore, TypeScript still assumes otherwise.
interface Array<T> {
// ...
filter<S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[];
}
To understand why this happens, we would have to take a look at the TypeScript type definition of the filter
function. The main thing to notice is that the predicate function, which is the callback that you define as the first function argument, is responsible for determining the type of values in the resulting array. This means that if the operation in the predicate doesn’t concretely result in a new type, the filter
function will assume that the array of objects before and after the function call has remained the same.
This is where most of the issues arise. Developers often define the predicate function inline, which means they’re leaving it all in the hands of TypeScript to derive the proper typings. Together with that, JavaScript has some non-conventional ways to check for nullable values. Think of the !!
operator or the Boolean
constructor approach that we mentioned earlier. While we as developers know these approaches work, they aren’t as clear-cut for TypeScript. This causes a mismatch in typing.
This article will cover different ways to sort out the typing when filtering nullable values from an array using TypeScript. These include inline type guarding, type casting, and a general utility function. Using this knowledge, you’ll be able to make your filter
function calls properly synchronize with TypeScript and enjoy the type derivation that you deserve.
Inline Type Guarding
In TypeScript, there exists the concept of type guarding. Basically, at the function definition level, you type the return value of a function as a type predicate rather than a concrete type. This indicates to TypeScript that whenever the function evaluates to a truthy value, the object is the same type as the result of the type predicate.
But instead of doing this on the function definition level, you’re also able to do this inline onto a callback. By leveraging this mechanic, you can type the return value of the filter
function callback using a type predicate of your desired type. Then you can use your preferred way of checking for a nullable value and TypeScript will automatically infer the non-nullable typing after the filter
call.
type SomeObject = { /* */ };
const arrayWithNullableValues: Array<SomeObject | null | undefined> = [/* */];
const arrayNonNullable = arrayWithNullableValues.filter((value): value is SomeObject => !!value);
Type Casting
Another approach to getting proper types onto a nullable filtered array is making use of type casting. Type casting is not a TypeScript specific concept, but exists in almost all type systems or typed programming languages. It’s a mechanic where the developer can forcefully tell the type system to consider a value to be a certain type. While not recommended, there are scenarios where they can be useful when developers are entirely sure about the results.
As the filter
function only accepts predicate functions, it’s impossible to affect the type of the resulting array by performing type casting inside the callback. Instead, it has to be performed on the variable level, after the filter
function is applied. As mentioned, with as Array<T>
we’re telling TypeScript to put aside everything they know about the array and consider it an array of type T
going forward.
type SomeObject = { /* */ };
const arrayWithNullableValues: Array<SomeObject | null | undefined> = [/* */];
const arrayNonNullable = arrayWithNullableValues.filter(value => !!value) as Array<SomeObject>;
General Utility Function
Lastly, one could also create a utility function which would do the filtering and make sure that the typing is done properly. Similar to the first approach, this makes use of type guarding. However, the difference is that the typing is defined with a standalone function rather than inline in the filter
function callback.
The typing itself isn’t different from the first approach that we looked into. Basically, we’re defining the return type of the function as a type predicate, indicating to TypeScript that the passed value is a non-nullable value of the utility function that returns a true value.
You can even make this utility function a generic one that can be reused for filtering non-nullable values for any object or value. To do so, you’ll have to change the typing definition of the function to make use of a generic type. Besides that, everything is the same and now you have a general utility function that will filter non-nullable values properly in TypeScript.
function isNonNullable<TValue>(value: TValue | undefined | null): value is TValue {
return value !== null && value !== undefined; // Can also be `!!value`.
}
type SomeObject = { /* */ };
const arrayWithNullableValues: Array<SomeObject | null | undefined> = [/* */];
const arrayNonNullable = arrayWithNullableValues.filter(isNonNullable);
Final Thoughts
No matter whether you’re using React, Node, or other forms of JavaScript library, a function that you’ll likely have used a lot is the Array filter
function. A common use case, especially in the realm of JavaScript development, is to filter out nullable values from an array. However, if you use this in combination with TypeScript, the typing doesn’t always end up as expected.
To solve this, this article went over 3 ways to sort out the typing when filtering out nullable values from an array using TypeScript. This includes applying inline type guarding onto the filter
function predicate, type casting of the resulting array, and using a general utility function that is type guarded. Using these methods, you’ll be able to filter nullable values from an array and get the appropriate typings.