В настоящее время я работаю над проектом в TypeScript (версия 2.9.2) и столкнулся с неожиданным полиморфным поведением. В Java и C # интерфейсы определяют полиморфное поведение в той же степени, что и классы, то есть в следующем случае верно, что item1
может иметь тип A
, как и то, что он может иметь тип B
, и что item2
может иметь тип C
, так как оно может иметь тип D
:
interface A { }
class B implements A { }
class C { }
class D extends C { }
Но в TypeScript, похоже, это не так. У меня примерно следующая настройка:
interface A {
new (str: string): Module;
someFunction(str: string): A;
}
class B implements A {
constructor(str: string) { /* ... */ }
someFunction(str: string): B { /* ... */ }
}
Компилятор, похоже, имеет проблему с типом возвращаемого значения B
someFunction()
, но по моему пониманию полиморфизма, поскольку B
реализует A
, если функция возвращает что-то типа A
тогда он также должен иметь возможность возвращать что-то типа B
. При этом не имеет смысла, что что-то должно «иметь тип A
», поскольку интерфейсы не могут быть созданы, и являются не более чем нематериальным соглашением или контрактом между классами. Тогда кажется разумным, что если бы A
вместо этого был абстрактным классом, полиморфное поведение должно вести себя так, как я ожидаю - и это действительно так, - но в рамках библиотеки, которую я строю, это кажется более подходящим для A
быть интерфейсом.
Проблема, с которой сталкивается компилятор, в частности, заключается в следующем в строке, которая объявляет B
s someFunction()
:
[ts]
Property 'someFunction' in type 'B' is not assignable to the same property in base type 'A'.
Type '(str: string) => B' is not assignable to type '(str: string) => A'.
Type 'B' is not assignable to type 'A'.
Types of property 'someFunction' are incompatible.
Type '(str: string) => B' is not assignable to type '(str: string) => A'.
(method) Project.B.someFunction(str: string): B
Часть проблемы, кажется, заключается в том, что я объявляю конструктор в A
. Если я удалю это определение конструктора, проблема будет решена, но мне нужно, чтобы это определение было частью соглашения о том, что в сущности означает тип A
.
Учитывая ожидаемое полиморфное поведение, как я могу написать свой интерфейс или вместо этого использовать абстрактный класс? Как мне вызвать это полиморфное поведение?