I have two classes:
class Dog {
run() {
console.log("RUN")
}
}
class Fish {
swim() {
console.log("SWIM")
}
}
I then make a type union through:
type Pet = Dog | Fish
I then use a type predicate to evaluate what is the superclass of Pet instances:
function isDog(pet: Pet): pet is Dog {
return (pet as Dog).run !== undefined
}
function isFish(pet: Pet): pet is Fish {
return (pet as Fish).swim !== undefined
}
I then have an array of Pets:
const zoo: Array<Pet> = [dog, dog, dog, fish, fish, fish]
I would like to filter the array having only Fish instances, I do:
const underwater: Array<Fish> = zoo.filter(isFish)
which works.
Why doesn't this work in the 'expanded' version of the filter function?
const underwater2: Array<Fish> = zoo.filter((p) => isFish(p))
This is the fifth case of open TypeScript issue #38390. Though it might be possible to infer type-predicate return types for simple cases, the main problem seems to be that it would be a breaking change.
Currently, this code type checks:
const pets = zoo.filter(x => isFish(x));
// const pets: Pet[]
pets.push(new Dog()); // Allowed
However, if a type predicate would be inferred for the arrow function, it would fail:
const pets = zoo.filter((p): p is Fish => isFish(p));
// const pets: Fish[]
pets.push(new Dog()); // Type error
If necessary, you can specify the type predicate in the return type of the arrow function (i.e. (p): p is Fish => isFish(p)):
const underwater2: Array<Fish> = zoo.filter((p): p is Fish => isFish(p))
// const underwater2: Fish[]
TypeScript playground
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With