Ответ 1
TypeScript Часть
До сих пор spec говорит, что за тегом extends
должен следовать TypeReference. И TypeReference должен быть в форме A.B.C<TypeArgument>
, например MyModule.MyContainer<MyItem>
. Итак, синтаксически ваш код прав. Но это не типичный случай.
В спецификации указано, что BaseClass
должен быть допустимым классом typescript. Однако спецификация устарела, как сказано в здесь. Теперь typescript допускает выражения в выражении extends, если выражения вычисляются функцией-конструктором. Это определение, на самом деле, основано на реализации. Вы можете увидеть здесь здесь. Проще говоря, выражение можно считать конструктором, если оно реализует интерфейс new() {}
.
ES2015 Часть
Итак, ваша проблема - простая функция, которая не распознается как конструктор в TypeScript, что можно утверждать, потому что спецификация ES2015 требует, чтобы объект имел внутренний метод [[construct]]
. Хотя пользовательский объект функции имеет его.
ES2015 требует BaseClass
является конструктором в во время выполнения. Объект isConstructor
, если он имеет [[construct]]
внутренний код. Спектр говорит, что [[construct]]
является внутренним методом для Объекта функции. Пользовательские функции являются экземплярами Function Objects
, поэтому, естественно, они являются конструкторами. Но встроенная функция и функция стрелки может не иметь [[construct]]
.
Например, следующий код будет вызывать время выполнения TypeError
, потому что parseInt
является встроенной функцией и не имеет [[construct]]
new parseInt()
// TypeError: parseInt is not a constructor
И из ECMAScript
Функции стрелок похожи на встроенные функции, поскольку оба они не имеют .prototype и любой внутренний метод [[Construct]]. Таким образом, new (() = > {}) выдает TypeError, но в противном случае стрелки похожи на функции:
Как правило, любая функция без prototype
не new
-able.
Работа вокруг
Короче говоря, не каждая функция является конструктором, typescript захватывает это, требуя new() {}
. Однако определяемая пользователем функция является конструктором.
Чтобы обойти это, самый простой способ - объявить Fn
как переменную и вставить его в конструктор.
interface FnType {}
var Fn: {new(): FnType} = (function() {}) as any
class B extends Fn {}
Рассуждение несовместимости
DISCALIMER: Я не основной разработчик typescript, а просто поклонник TS, у которого есть несколько побочных проектов, связанных с TS. Итак, этот раздел - моя личная догадка.
TypeScript - проект, созданный в 2012, когда ES2015 все еще надвигался в темноте. typescript не имел хорошей ссылки на семантику класса.
В то время главная цель typescript заключалась в том, чтобы поддерживать совместимость с ES3/5. Таким образом, new
функция является законной в TypeScript, поскольку она также является законной в ES3/5. В то же время typescript также нацелено на захват ошибок программирования. extends
функция может быть ошибкой, потому что функция может быть не разумным конструктором (скажем, функцией исключительно для побочного эффекта). extends
даже не существовало в ES3/5! Таким образом, typescript может свободно определять свое использование extends
, поэтому extends
должен быть сопряжен с переменной class
. Это сделало typescript больше TypeSafe, будучи совместимым с JavaScript.
Теперь спецификация ES2015 завершена. JavaScript также имеет ключевое слово extends
! Тогда возникает несовместимость. Для устранения несовместимости существуют усилия. Однако все еще существуют проблемы. Тип () => void
или Function
не должен расширяться, как указано выше из-за встроенной функции. Следующий код сломается
var a: (x: string) => void = eval
new a('booom')
С другой стороны, если a ConstructorInterface
был введен в typescript, и каждый реализованный им литерал функции, то возникла бы обратная несовместимость. Следующий код компилируется сейчас, но не тогда, когда был введен ConstructorInterface
var a = function (s) {}
a = parseInt // compile error because parseInt is not assignable to constructor
Конечно, команда TS может иметь решение, которое балансирует эти два варианта. Но это не является первоочередной задачей. Кроме того, если сальса, кодовое имя для JavaScript, основанного на TS, полностью реализована. Эта проблема будет решена естественным образом.