function isString(v: unknown): boolean {
return typeof v === "string";
}
function shout(v: string | number) {
if (isString(v)) {
return v.toUpperCase();
}
return v.toFixed(1);
}
Both
toUpperCase and toFixed error, because a boolean return type does not narrow vBoth calls error. The function is annotated to return boolean, and a plain boolean gives the caller no type information. So v stays string | number in both branches. toUpperCase does not exist on number, and toFixed does not exist on string.
The option "It compiles, because isString checks typeof internally" is wrong. TypeScript does not look inside the function body for this. To fix it, annotate the return type as v is string, which is a type predicate.
Since TypeScript 5.5, TypeScript can infer a predicate for an unannotated function like this. But the explicit boolean annotation stops that from happening.
Read more