抽象化 - 関数を持つ TypeScript インターフェース。インターフェースを実装する際に、パラメータとしてのサブタイプは受け入れられない
私は以下のように別のクラスを拡張するクラスを持っています
abstract class FooAbstract{
constructor(someProp:any){
this.someProp = someProp;
}
someProp:any;
}
class Foo extends FooAbstract{
constructor(prop:any){
super(prop);
}
someRandomFunction(){
console.log("Something")
}
}
私は以下のような関数を持つインターフェースを持っています
interface ExampleInterface{
someFunction: (foo:FooAbstract)=>any;
}
次にインターフェースを実装したいのですが、以下のようにインターフェースの実装内で関数someFunctionのパラメータとしてサブタイプを渡したいです
class Example implements ExampleInterface{
someFunction = (foo:Foo)=>{
console.log("Hello World");
}
}
TypeScriptは、someFunction の実装が正しくないこと、そして型 Foo と FooAbstract が互換性がないことを警告しています。なぜ FooAbstract のサブタイプをパラメーターとして要求することで someFunction を実装できないのか、理解したいです。
回答 #1
実際、これは意味があります。なぜなら、これを行うのは安全ではないからです。次のシナリオを考えてみてください:
class Example implements ExampleInterface{
someFunction = (foo:Foo)=>{
console.log("Hello World");
foo.someRandomFunction() // we can call this since foo is of type Foo
}
}
class Boo extends FooAbstract{
constructor(prop:any){
super(prop);
}
// no someRandomFunction method
}
var ex: ExampleInterface = new Example();
ex.someFunction(new Boo({})) // ok, Boo is derived from FooAbstract
もしコンパイラがあなたの質問のシナリオを許可するなら、上記のコードはコンパイルされますが、someRandomFunction が Boo に存在しないため、実行時に失敗します。
インターフェースをジェネリックにすることで、使用する派生FooAbsrtactの種類を指定できるようにできます:
interface ExampleInterface< T extends FooAbstract >{
someFunction: (foo:T)=>any;
}
// now ok
class Example implements ExampleInterface<Foo>{
someFunction = (foo:Foo)=>{
console.log("Hello World");
foo.someRandomFunction()
}
}
class Boo extends FooAbstract{
constructor(prop:any){
super(prop);
}
// no someRandomFunction method
}
var ex: ExampleInterface<Foo> = new Example();
ex.someFunction(new Boo({})) // compile error as it should be
