Reputation: 333
I have an array which may have two types A
and B
. I would like to perform actions over items of one type.
type A = {
propA: number
}
type B = {
propB: string
}
type MyArray = Array<A|B>
const anArrayOfBothAAndB: MyArray = [{ propA: 1 }, { propB: '2' }]
anArrayOfBothAAndB.filter((item) => {
return (item as A).propA
})
.forEach((item: A) => { // reports error here
console.log(item.propA)
})
I can add code like const itemA: A = item as any
to make console.log(itemA.propA)
work, but it looks not elegant.
Upvotes: 3
Views: 1824
Reputation: 108
Well, since 2020, some things have changed in the TypeScript world. The filter
method may be used with a generic parameter. Here's the perfect example, also with the filter
method ;)
Given the code snippet you've pasted here.
type A = {
propA: number
}
type B = {
propB: string
}
type MyArray = Array<A|B>
const anArrayOfBothAAndB: MyArray = [{ propA: 1 }, { propB: '2' }]
anArrayOfBothAAndB.filter((item) => {
return (item as A).propA
})
.forEach((item: A) => { // reports error here
console.log(item.propA)
})
There should be a difference in the first filter()
call, so it should be like this:
anArrayOfBothAAndB.filter<A>((item): item is A => {
return 'propA' in item;
}).forEach((item) => {
console.log(item.propA)
})
The difference is that you pass a predicate function
(also called type guard
) as the filter
callback. So you give to the filter
this guard which assures the new array that it's the type you predicate.
Upvotes: 0
Reputation: 1905
Your issue is that TypeScript isn't smart enough to detect that all elements of the array should be of type A
after the filtration. You need to declare the return type of the filter function as item is A
. See the documentation here.
Fixed version:
type A = {
propA: number
}
type B = {
propB: string
}
type MyArray = Array<A|B>
const anArrayOfBothAAndB: MyArray = [{ propA: 1 }, { propB: '2' }]
anArrayOfBothAAndB.filter((item): item is A => {
return (item as A).propA !== undefined
})
.forEach((item) => { // no more error, don't even have to specify type
console.log(item.propA)
})
Upvotes: 9