In JavaScript, all functions have a special property called prototype. If you use a function as a constructor (by calling it with new), the constructed instance will have that as its prototype. This is how classes worked in JavaScript before ES2015:
// ES5-flavored class
function Foo() { } // a normal function
Foo.prototype.prop = 0; // adding a property to Foo.prototype
var f = new Foo(); // using Foo as a constructor
f.prop; // the instance inherits the added property
ES2015 introduced the class syntax, which behaves the same way under the hood... and so constructor objects still have a prototype property from which constructed instances inherit.
// ES2015-flavored class
class Foo { } // explicitly a class
Foo.prototype.prop = 0; // adding a property to Foo.prototype
const f = new Foo(); // using Foo as a constructor
f.prop; // the instance inherits the added property
TypeScript models this by declaring that the Function interface, which all functions implement, has a prototype property of type any. Furthermore, when the class syntax is used, the constructor is still seen as a Function, and the prototype property of the constructor is narrowed from any to the same type as the constructed class instance:
// TypeScript code
class Foo {
prop!: number; // Foo has a prop
}
Foo.prototype; // inspects as type Foo
Foo.prototype.prop = 0; // so this works
const f = new Foo(); // inspects as type Foo
f.prop; // inspects as type number
Even abstract classes in TypeScript have a prototype property whose type is the same as the instance type. So while you can't call new on an abstract class constructor, or match it to a newable type like new() => any, you can still talk about its prototype:
// more TS code
abstract class Bar {
abstract prop: number;
}
Bar.prototype; // inspects as type Bar
Bar.prototype.prop = 0; // so this works
const b = new Bar(); // whoops can't do this though
All this means that in TypeScript a possibly-abstract class constructor is (a subtype of) a Function whose prototype property is the instance type for the constructor. Thus, you can say that
type PossiblyAbstractConstructor<T> = Function & {prototype: T};
using the intersection operator to combine Function and "object with a prototype property of type T"...
or similarly
interface PossiblyAbstractConstructor<T> extends Function {
prototype: T;
}
using interface extension to achieve the same effect...
and you know that the following is valid:
const fooConstructor: PossiblyAbstractConstructor<Foo> = Foo;
const barConstructor: PossiblyAbstractConstructor<Bar> = Bar;
That should explain how the original question's answer is applicable. Hope that helps. Good luck!