Let’s say I have an object of type:
type BulkItem = { id: number; type: 'bulk'; tonnage: number }
type RegularItem = { id: number; type: 'regular'; weight: number }
export type CartItem = BulkItem | RegularItem // there could be more item types here
Now, in my component, let’s say I get a list of CartItem
s that I want to map across and display things.
const items = getCartItems(...)
<div>
{items.map(item => {
switch(item.type) {
case 'regular': return (<div>Weight: {item.weight}</div>)
case 'bulk': return (<div>Tonnage: {item.tonnage}</div>)
}
})}
</div>
Now, I get a TS error saying that item.weight
does not apply to CartItem
because bulk items don’t have a weight
property. Likewise, item.tonnage
does not apply to CartItem
because regular items don’t have a tonnage
property.
I know this is kind of a contrived example but I’m basically asking if there’s a way to coerce each item in a list to be of a type that I would expect it to be in each case of the switch statement?
2
Answers
Actually, there is no typescript bug in your code, unless the
getCartItems
returnsCartItem[]
.If the typescript still gives error, you can use Type Guard Functions to identify a
CartItem
is aBulkItem
orRegularItem
.Then, employ type narrowing with
if
statements:There’s 2 different types that you could be referring to here.
Your switch statement is checking on a string property named
'type'
, and not necessarily the typeScript'type'
.If you want to use the switch statement for the string
'type'
You can restructure your TS types to just be one model i.e.
Then your switch statement could stay the same, if you want.
If you want to keep your TS
types
as-isYou can change your switch statement to check the actual TS ‘type’