#Using type predicates

23 messages · Page 1 of 1 (latest)

onyx token
#

Hi, I'm reading through the TS docs and I'm currently at the Type Predicates section.
As an example they have this snippet:

type Fish = { swim: () => void };
type Bird = { fly: () => void };
function isFish(pet: Fish | Bird): pet is Fish {
  return (pet as Fish).swim !== undefined;
}

And my question is if the function isFish and isFish2 have the same functionality in the next snippet, and if not, why? Both console.log work.

type Fish = { swim: () => void };
type Bird = { fly: () => void };
function getSmallPet(): Fish | Bird {
  return Math.random() >= 0.5 ? {swim() {}} : {fly() {}}
}
function isFish(pet: Fish | Bird): pet is Fish {
  return (pet as Fish).swim !== undefined;
}
function isFish2(pet: Fish | Bird): boolean {
  return "swim" in pet
}

const pet = getSmallPet()
if (isFish(pet)) console.log("is Fish according to isFish")
if (isFish2(pet)) console.log("is also Fish according to isFish1")

I'm having a hard time understanding the use case for type predicates, they just seem unnecessarily verbose to me when isFish2 does the same (I think), with less code.

#

Using type predicates

spring lion
#

the goal of such a function is to narrow the type of the parameter for the rest of the code
and to tell TypeScript the exact type the object, the return type matters (pet is Fish)
if the condition is true, TypeScript is sure the pet is a Fish for the rest of the code

#

whereas a simple boolean function would perform the check once, but then the TypeScript compiler sould not narrow the type of the object

onyx token
#

true, I didn't notice that, thanks

dusty sealBOT
#
Ascor8522#7606

Preview:```ts
type Fish = {swim: () => void}
type Bird = {fly: () => void}
function getSmallPet(): Fish | Bird {
return Math.random() >= 0.5
? {swim() {}}
: {fly() {}}
}

function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined
...```

spring lion
#

!ts result1 result2

dusty sealBOT
#
const result1: Fish /* 16:9 */``````ts
const result2: Fish | Bird /* 19:9 */```
spring lion
#

result1 has been narrowed wheras result2 has not

#

tho the way you do the check and return the boolean doesn't matter

#

and doing (pet as Fish).swim !== undefined or "swim" in pet does the same thing

onyx token
#

that's so much better

#

the original return statement seems so convoluted to me

#

thanks a lot

spring lion
#

well, since you don't know if it's a Fish or a Bird, you can try to access one property and see if it's defined or not

#

but to access that property, you need to ues a cast and tell the compiler you are sure that object will be a Fish (even tho we are just testing if it is a Fish or not)

onyx token
#

so using just "swim" in pet is wrong? :/

spring lion
#

no

#

doing pet.swim won't work since you are trying to access a property that might not exist

#

however, using "swim" in pet, we do not try to access it, we just check if it is defined or not, so this is allowed

onyx token
#

alright, that's all I needed to know

#

appreciate it