loading...

Filtering in TypeScript

icyjoseph profile image Joseph ・2 min read

Say that you have this type:

type List = (Subject | null | undefined)[]

Perhaps it is the result of querying for a list of identifications, where not every entry is guaranteed to have a result.

Nothing strange so far. However, let's say you now want to remove null and undefined elements, in order to do a further operation on the leftover Subject elements.

interface Subject {
    id: string | number
    name: string
}

type List = (Subject | null | undefined)[]

const joe: Subject = { id: 0, name: 'joe' }
const jane: Subject = { id: 10, name: 'jane' }
const list: List = [joe, null, undefined, jane]

const names = list.filter(entry => !!entry).map(entry => entry.name)

console.log(names)

Unfortunately this does not work:

TSError: ⨯ Unable to compile TypeScript:
index.ts:12:58 - error TS2533: Object is possibly 'null' or 'undefined'.

We need to tell TypeScript that the filter operation ensures only Subject types are left.

function exists<T>(value: T | null | undefined): value is T {
    return value === (value ?? !value)
}

The exists function, for example, makes sure to assert that value is of type T.

In production code, try to avoid generic naming such as T

To filter and have Subject types as leftover:

interface Subject {
    id: string | number
    name: string
}

type List = (Subject | null | undefined)[]

const joe: Subject = { id: 0, name: 'joe' }
const jane: Subject = { id: 10, name: 'jane' }
const list: List = [joe, null, undefined, jane]

function exists<T>(value: T | null | undefined): value is T {
    return value === (value ?? !value)
}

const names = list.filter(exists).map(entry => entry.name)

console.log(names) // [ "joe", "jane" ]

That's all! Now TypeScript makes sure that name is available on the filtered items.

Type guards are fun!

Discussion

pic
Editor guide
Collapse
andrewbaisden profile image
Andrew Baisden

Vey cool and easy to understand thanks for sharing.