how do i make a class method user type guard work in typescript?

As you are aware, one of the call signatures of the Array<T>.filter() method in the standard TypeScript library will narrow the type of the returned array’s element when you pass in a user-defined type guard function as its parameter:

 interface Array<T> {
   filter<S extends T>(
     callbackfn: (value: T, index: number, array: T[]) => value is S, 
     thisArg?: any
   ): S[];

The hasName() function is a user-defined type guard, and that works.

But when you call it with a => a.hasName() instead, the type of that function is inferred to return just boolean. That’s because user-defined type guard functions do not propagate and are not inferred for you; see microsoft/TypeScript#10734. A type like x is Y generally gets widened to boolean by the compiler as soon as you start doing things with it.

You could tell the compiler that your arrow function callback is also a type guard by using an arrow-function return type annotation, like this:

const listA = [new A('John'), new A(), new A('Mark')].filter(
  (a): a is A & { name: string } => a.hasName()

Note that the type predicate is a is A & {name: string} instead of just a is {name: string}. That’s because, strictly speaking, a type predicate must narrow the value in question, and {name: string} is not a subtype of A (since {name:string} is missing the hasName() method). You can apparently get away with this is {name: string} in a method because polymorphic this is not checked as strictly in a type predicate (as implemented in microsoft/TypeScript#5906). Anyway, the intersection A & {name: string} fixes it.

Playground link to code

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top