В JavaScript все функции имеют специальное свойство, называемое prototype
. Если вы используете функцию в качестве конструктора (вызывая ее с помощью new
), созданный экземпляр будет иметь ее в качестве прототипа. Вот как классы работали в JavaScript до 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 ввел синтаксис class
, который ведет себя так же под капотом ... и поэтому у объектов-конструкторов все еще есть свойство prototype
, от которого наследуются построенные экземпляры.
// 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 моделирует это, заявляя, что интерфейс Function
, который реализуют все функции, имеет свойство prototype
типа any
. Кроме того, когда используется синтаксис class
, конструктор по-прежнему рассматривается как Function
, а свойство prototype
конструктора сужается с any
до того же типа, что и построенный экземпляр класса:
// 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
Даже классы abstract
в TypeScript имеют свойство prototype
, тип которого совпадает с типом экземпляра. Поэтому, хотя вы не можете вызвать new
в конструкторе абстрактного класса или сопоставить его с новым типом, таким как new() => any
, вы все равно можете говорить о его 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
Все это означает, что в TypeScript возможно абстрактный конструктор класса является (подтипом) Function
, чье свойство prototype
является типом экземпляра для конструктора. Таким образом, вы можете сказать, что
type PossiblyAbstractConstructor<T> = Function & {prototype: T};
с использованием оператора пересечения для объединения Function
и "объекта со свойством prototype
типа T
" ...
или аналогично
interface PossiblyAbstractConstructor<T> extends Function {
prototype: T;
}
с использованием расширения интерфейса для достижения того же эффекта ...
и вы знаете, что действует следующее:
const fooConstructor: PossiblyAbstractConstructor<Foo> = Foo;
const barConstructor: PossiblyAbstractConstructor<Bar> = Bar;
Это должно объяснить, как применим оригинальный ответ на вопрос. Надеюсь, это поможет. Удачи!