Как `type Constructor <T>= Function & {prototype: T}` применяется к абстрактным типам конструктора в TypeScript? - PullRequest
0 голосов
/ 16 сентября 2018

В «TypeScript» есть вопросы и ответы о типах конструктора Abstract, на которые я бы хотел узнать ответ:

Абстрактный тип конструктора в TypeScript

К сожалению, принятый ответ немного больше, чем необъяснимый однострочный: type Constructor<T> = Function & { prototype: T }

Похоже, что этот ответ достаточно хорош для спрашивающего, это принятый ответ, но я не могу понять, как ответ применим к вопросу.

Я пытался спросить в комментариях и пытался попросить кого-нибудь в чате объяснить ответ, но безрезультатно. Кроме того, я признаю, что этот вопрос едва ли отличается от этого вопроса, но это все еще уникальный вопрос о коде.

Как я могу использовать тип Function & { prototype: T } для эмуляции абстрактного класса известного типа конструктора?

1 Ответ

0 голосов
/ 16 сентября 2018

В 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;

Это должно объяснить, как применим оригинальный ответ на вопрос. Надеюсь, это поможет. Удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...