Leveraging TypeScript Type Guards for Precise Filtering in Arrays

Since functional programming gained popularity in the JavaScript world, a trio of array methods—namely, map, filter, and reduce—have also risen to prominence. These methods became go-to tools for two primary reasons:
They're simpler for doing basic looping with arrays.
They allow method chaining, resembling the builder design pattern, enhancing coding flexibility.
Problem
However, there's a catch when using TypeScript's filter. Consider the following code:
const posts = [
{id: 0, title: "Title 1", content: "Content 1"},
{id: 1, title: "Title 2", content: "Content 2"},
{id: 2, title: "Title 3", content: "Content 3"},
null,
undefined
];
const filteredPosts = posts.filter(post => post != null);
Surprisingly, TypeScript infers filteredPosts as a mix of valid posts and null values (i.e. ({id: number, title: string, content: string} | null)[]). How can we ensure TypeScript infers the correct type?
Type Guard
Fortunately, TypeScript offers a solution through type guards, expressions that perform runtime checks, ensuring correct type inference. Let's see it in action:
// Constructed this type for convenience
type Post = {id: number, title: string, content: string};
const posts = [
{id: 0, title: "Title 1", content: "Content 1"},
{id: 1, title: "Title 2", content: "Content 2"},
{id: 2, title: "Title 3", content: "Content 3"},
null,
undefined
];
const filteredPosts = posts.filter((post): post is Post => post != null);
Now, TypeScript understands filteredPosts as an array containing only Post (i.e. {id: number, title: string, content: string}[]).
Improving Reusability
Let's level up our function's versatility using generics and TypeScript's NonNullable utility type:
const posts = [
{id: 0, title: "Title 1", content: "Content 1"},
{id: 1, title: "Title 2", content: "Content 2"},
{id: 2, title: "Title 3", content: "Content 3"},
null,
undefined
];
const chooseNonNullable = <T>(arg: T): arg is NonNullable<T> => arg != null;
const filteredPosts = posts.filter(chooseNonNullable);
Now, you can export chooseNonNullable and use it as a callback to any filter methods to remove both null and undefined.
Addressing an Alternative
You might wonder about using the as keyword instead of type guards. While possible, it's less reliable as it assumes a type without verification, leading to potential errors. Stick with type guards for accuracy and safety!




![[TWIL] Week of August 11, 2024](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1724192926501%2F2ba38d69-5f89-4c41-b2fe-7f994fa97f71.png&w=3840&q=75)
![[TWIL] Week of August 04, 2024](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1723410046529%2F77c9c1f6-e0e2-4422-aa2c-0b82b769631c.png&w=3840&q=75)
![[TWIL] Week of July 28, 2024](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1723335244607%2F22b5f8ee-4c35-4cf0-9666-405c09aae03c.png&w=3840&q=75)