... продолжение
Важный вопрос — как конструировать любой вид
*<
*>?
Аргумент вида стоит воспринимать как тип, который каким-либо образом будет использоваться в контексте типов?
Например, тогда тип промиса может быть выражен как Promise<Number>. (например, как для выражения
Promise.resolve(5), так и для выражения
new Promise(resolve => resolve(5)))
Такой тип может быть указан рядом с именем определяемого класса.
class Option<T> {
constructor(T value) {
this.value = value;
}
}
new Option(5); // имеет тип Option<Number>, выводится по тому, как используется
Или же стоит воспринимать аргумент вида как параметр конструктора типа (или как одну из перегрузок конструктора типа)? Тогда, поскольку конструктор типа Promise требует функцию, то тип выражения new Promise(resolve => resolve(5)) будет записан так Promise<Function<Function<Number, void>, void>>
class Option {
constructor(Number value) {
this.value = value;
}
}
new Option(5); // имеет тип Option<Number>, выводится по тому, как описано в конструкторе
Теперь немного про типизированные выражения. Любое вычисленное выражение expr имеет тип. Простой тип может быть получен при помощи
expr.constructor. Составной тип получается таким же образом, но для его аргументов нужно что-то отдельное, например специальный символ
Symbol.typeArguments
Приведённый в начале пример может быть явно обозначен типами так:
const PI = 3.14159265 :: Number;
const re = /a/gi :: RegExp;
const IS_PROXY = Symbol("is proxy") :: Symbol;
const now = new Date() :: Date;
Составные типы:
const xs = [2, 3, 5, 7, 11, 13] :: Array<...Number>;
const pair = [/.*/, document.createElenet("div")] :: Array<RegExp, HTMLElement>;
Тут простой тип выводится через
pair.constructor, а параметры типа узнаются через
pair[Symbol.typeArguments]
Вот, например, заготовка для класса Rect, представляющего некий абстрактный прямоугольник.
class Rect {
constructor(Number x, Number y, Number width, Number height) {}
constructor(Vector2 position, Vector2 size) {}
constructor(Array<Number, Number, Number, Number> [x, y, width, height]) {}
constructor(Rect { x, y, width, height }) {}
}
class Vector2 {
constructor(Number x, Number y) {
this.x = x;
this.y = y;
}
}