Slevin
Slevin

Reputation: 4222

Typescript's TypeGuard lost in enumerator

Looking at the following code, I don't understand why filter.formatter (in the penultimate line) could be undefined since I have checked it's presence before:

type Filter = {
    formatter?: {
        index: number,
        func: (value: string) => void
    }
}

const filter: Filter = {
    formatter: {
        index: 1,
        func: (v) => {
            return `Label: ${v}`
        }
    }
}

const data = [['foo', 'bar']]

if (filter.formatter) {
    data[filter.formatter.index].forEach(d => {
        filter.formatter.func(d) // <-- `formatter` is possibly undefined
    })
}

TypeScript Playground

Update 1

As @CRice mentionend in the comment, this doesn't happen in for-loops. But I still wonder why?

Updated TypeScript Playground

Upvotes: 0

Views: 58

Answers (1)

Arnaud Claudel
Arnaud Claudel

Reputation: 3138

You can re-write the code like this to better understand the error.

if (filter.formatter) {
    const itemConsumer = (d: string) => { filter.formatter.func(d) };
    data[filter.formatter.index].forEach(itemConsumer);
}

// both are the same

const itemConsumer = (d: string) => { filter.formatter.func(d) };
if (filter.formatter) {
    data[filter.formatter.index].forEach(itemConsumer);
}

Here in itemConsumer, you just capture the reference to filter but not its actual value.
Therefore, filter.formatter could become null before itemConsumer is executed.

It's not the case with the for loop because you don't create a new function for it, so you use filter value and the compiler can be sure that filter.formatter cannot be undefined.

If you want to know more about this, there is a serie of books about JS and one dedicated to scope and closure

Upvotes: 2

Related Questions