Would you believe me if I told you C actually is a subtype of A? Typescript is structurally typed, so any object that implements a given interface for A is considered a valid value of type A. Since A's interface is {} (i.e. no interface at all), any Javascript object is an value of type A.
If the interfaces don't match, then the subclass check will fail.
class A {foo() {}}
class B extends A {}
class C {}
Now C is not a subtype of A. If you want to be absolutely sure, you can make a private field. Private fields are never compared structurally, so a private field on A can only ever be present in actual subclasses of A.
class A {private _placeholder: null = null}
class B extends A {}
class C {}
There's a distinction between subclassing and subtyping here. In some languages like Java, the two are similar enough that you can treat them as interchangeable in many situations, but not so in Typescript. In your first code example, B is a subclass of A (because it subclasses it with the extends keyword, or moreover because A appears in the prototype chain for instances of B). However, C and B are both subtypes of A (since instances of either can safely be substituted anywhere a value of type A is expected). In general, every subclass relationship defines a subtype relationship, but not every subtype relationship is defined by a subclass relationship.
This is also true of union and intersection types. It's completely accurate to say that string is a subtype of number | string, since a string can always be safely treated as a number | string, but it's not accurate to say that string is a subclass of number | string (not least of all since neither of the things mentioned is a class).
return undefinedinfoofunction!