
Type Predicate는 함수가 어떤 타입을 반환함으로써 인자를 좁힐 수 있게 되는 타입 문법이다.
조금 말이 헷갈리는데 타입스크립트를 작성하다 보이는

반환 타입을 ~ is string로 작성하는 애들이다. 그냥 as와 비슷한 문법이라고만 생각하고 왜 ~ is string 이런 식으로 쓰는 건지 구체적으로 찾아보진 않았는데, 이참에 알아봐야겠다.

이렇게 undefined를 필터하는 함수가 있다고 가정해보자. filter를 통해 undefined를 제거했지만, filteredValues의 타입은 string[]이 아니라 여전히 (string | undefined)[]이다.

타입스크립트는 filter 함수가 타입을 좁히는 함수라고 인식하지 못하는 것이다. filter 후 반환 타입이 string[]가 되게 하려면 어떻게 해야할까?

제일 쉬운 방법은 as를 씌우는 것이다. 하지만 as를 씌우게 되면 런타임 상에서 undefined가 남아 있을 수 있는데, 타입스크립트는 타입 체킹을 포기하게 된다. 즉, 안전하지 않다.
이때 사용할 수 있는 것 Type Predicate다. 위에서 말했던 것처럼 Type Predicate는 함수가 어떤 타입을 반환한다고 명시하면서 인자를 좁힐 수 있는 문법이다.

이런 식으로 value is string을 명시하여 안전하게 추론할 수 있도록 한다.
단, Type Predicate도 as와 마찬가지로 런타임 동작을 보장하지 않는다.
이제 Assertion Functions을 알아보자. Assertion Functions는 Type Predicate보다 한 단계 더 강력하게 타입을 좁힐 때 쓴다.

이렇게 role을 체킹하는 함수가 있다고 가정하자.

role이 normal인 값이 들어오면 에러를 던진다. aasertUserIsAdmin에서 걸려졌으니 user.role은 "admin"만 남게 될까? 하지만 aasertUserIsAdmin아래 코드를 보면

여전히 user를 유니언으로 추론한다. 왜냐면 assertUserIsAdmin은 단순히 런타임 체크이기 때문이다. 타입 레벨에선 달라진 것이 없다.
이때, Type Predicate를 사용할 수 있다.

이렇게 좁혀주는 함수를 하나 만들고

함수 내부에서 추론하면 추론이 잘 된다.
assert문법은 이 과정을 한 번에 해결하면서 스코프에서도 타입 체킹을 하게 해준다.

함수의 반환 타입을 수정한뒤

처음과 같은 상황에서 user.role의 타입을 보면 제대로 좁혀진 것을 알 수 있다.
assert를 하다보면 이상한 점이 있다. function키워드가 아닌 화살표 함수로 작성했을 때 에러가 나온다.

위에서 작성했던 함수를 화살표 함수로 변경하게 되면

요런 에러와 직면한다. 이유는 assert는 함수 시그니처의 일부라서 화살표 함수 표현식에서는 안전하게 추론할 수 없기 때문이다(정확히 무슨 원인인지는 모르겠다)
쉽게 말해서 표현식 기반의 함수에서는 asssert가 되지 않는다고 타입스크립트에서 정한 것이다.
꼭, 화살표 함수로 작성해야 한다면

타입을 분리하면 정상 작동한다.