Search code examples
typescripttypescript-typingstypescript-types

How to convince TypesSript you will return an Array with a property that is not null


I am working with the following types:

type Fruits = {
    type: 'banana' | 'peach' | 'kiwi',
    price: null | string; 
}


type FruitsWithNonNull = Pick<Fruits, 'type'> & {
    price: NonNullable<Fruits['price']>
} 

const fruits:Fruits[] = [{type:'banana', price:null}, {type:'peach',  price:null},{type:'peach', price:'12'}]

const filteredFruits:FruitsWithNonNull[] = fruits.filter(fruit => fruit.price !== null);

I get this error from filteredFruits:

Type 'Fruits[]' is not assignable to type 'FruitsWithNonNull[]'.
  Type 'Fruits' is not assignable to type 'FruitsWithNonNull'.
    Type 'Fruits' is not assignable to type '{ price: string; }'.
      Types of property 'price' are incompatible.

how can I convince typescript that when the filtering of the fruits is happening then the price is guaranteed to be there?

here is a link to the typescript playground

I am not that confident with typescript yet so not sure what the solution is here.


Solution

  • You can accomplish this with a user-defined type guard

    type Fruits = {
        type: 'banana' | 'peach' | 'kiwi',
        price: null | string; 
    }
    
    
    type FruitsWithPrice = Pick<Fruits, 'type'> & {
        price: string;
    }
    
    const fruits: Fruits[] = [{type:'banana', price:null}, {type:'peach',  price:null},{type:'peach', price:'12'}];
    
    const isFruitWithPrice = (x: any): x is FruitsWithPrice => {
        return x?.price !== null;
    }
    
    const filtered: FruitsWithPrice[] = fruits.filter(isFruitWithPrice)
    

    Playground