TypeScriptクラスと同じ名前のインターフェイス間の特殊な関係の明確なドキュメントまたは説明を見つけるのに少し問題があります。
コード:
// Co-named interface and class doesn't like readonly property implementation:
interface Foo {
readonly x: number; // Error: Duplicate identifier 'x'
y: number;
}
class Foo {
get x(): number { // Error: Duplicate identifier 'x'
return 0;
}
y = 1;
}
// Same as above, but different class name + explicit `implements`
class Bar implements Foo {
get x(): number { // No error!
return 0;
}
y = 1;
}
// Duplicating the first example, but explicitly implementing the co-named interface:
interface Baz {
readonly x: number; // Error: Duplicate identifier 'x'
y: number;
}
class Baz implements Baz {
get x(): number { // Error: Duplicate identifier 'x'
return 0;
}
y = 1;
}
モジュール内の同じ名前のインターフェース マージされます :
_interface Foo {
x: number;
}
interface Foo {
y: string;
}
let g = {} as Foo;
g.x; // OK
g.y; // OK
_
クラス宣言は コンストラクタ関数と型宣言の両方 を作成します。これは基本的に、すべてのクラスをインターフェイスとして使用できることを意味します。
_class Bar {
y: number;
}
interface IBaz extends Bar { } // includes y: number
class CBaz implements Bar {
y: number = 5;
}
_
したがって、同じ名前のクラスとインターフェイスを持つことは、同じ名前の2つのインターフェイスを持つことと同等であり、インターフェイスの両方のインスタンスが異なる型の同じメンバーを再宣言すると、マージの競合が発生します。
奇妙なことに、TypeScriptはこれを可能にします。
_export interface Foo {
readonly x: number;
}
export class Foo {
readonly x: number = 3;
}
_
しかし、これらは両方とも_readonly x: number
_として生成されますが、get x() { return 3; }
を許可しません。したがって、型チェッカーは、意味的に同じであるにもかかわらず、マージ中にそれらを異なるものと見なすことしか想像できません(これはこれが、インターフェースを拡張し、readonlyプロパティをゲッター関数として指定できる理由です)。