[[Union]]인 변수가 존재할 때 하나의 타입으로 좁히고 싶을 때 `type predicates` 가 유용하다.
```typescript
const values = ["a", "b", undefined, "c", undefined];
const filteredValues = values.filter((value) => Boolean(value));
```
위의 예제에서 `values`의 타입은 `(string | undefined)[]`인데 `filter`함수를 실행시키면 `filteredValues`의 타입은 `string[]`으로 예상하지만 실제로는 `(string | undefined)[]` 으로 추론이 되어버린다.
![[filtered value.png]]
`string | undefined` [[Union]] 타입에서 하나의 타입(`string`)으로 추론시키기 위해서 아래와 같이 `filter` 에 넘겨주는 `predicate function` 리턴 타입을 `value is string`으로 지정하면 우리가 원하는 타입으로 추론이 된다.
```typescript
const filteredValues = values.filter((value): value is string => Boolean(value));
```
Type predicates 사용은 함수에서만 가능하다. 사용법은 함수 리턴 타입 지정하는 곳에 `(매개 변수) is (타입)` 형태로 코드를 작성하고 **반드시 함수에서 리턴하는 타입은 Boolean 이어야 한다.**
한가지 예를 더 살펴보면,
```typescript
interface User {
speak(): void
}
interface Dog {
howl(): void
}
function isDog(creature: User | Dog): creature is Dog {
return creature.howl !== undefined
}
const creature: User | Dog = {howl: () => {}}
if (isDog(creature)) {
creature.howl() // Dog로 타입 추론
}
```
`isDog` 함수에 [[Union]]타입을 넘겨주면 (유저 또는 개) `isDog` 함수 내부에서는 `howl` 함수가 존재하는지 확인한다. 앞서 말한 대로 반드시 boolean 타입을 리턴하면 `isDog` 실행 후 조건문 내부에선 `creature`가 `User`또는 `Dog`가 아닌 `Dog`로 추론이 된다.
---
참조 강의: https://inf.run/FVDi