I read through the TypeScript Coding guidelines
And I found this statement rather puzzling:
Do not use "I" as a prefix for interface names
I mean something like this wouldn't make a lot of sense without the "I" prefix
class Engine implements IEngine
Am I missing something obvious?
Another thing I didn't quite understand was this:
Classes
For consistency, do not use classes in the core compiler pipeline. Use function closures instead.
Does that state that I shouldn't use classes at all?
Hope someone can clear it up for me :)
ベストアンサー1
When a team/company ships a framework/compiler/tool-set they already have some experience, set of best practices. They share it as guidelines. Guidelines are recommendations. If you don't like any you can disregard them. Compiler still will compile your code. Though when in Rome...
This is my vision why TypeScript team recommends not I
-prefixing interfaces.
Reason #1 The times of the Hungarian notation have passed
Main argument from I
-prefix-for-interface supporters is that prefixing is helpful for immediately grokking (peeking) whether type is an interface. Statement that prefix is helpful for immediately grokking (peeking) is an appeal to Hungarian notation. I
prefix for interface name, C
for class, A
for abstract class, s
for string variable, c
for const variable, i
for integer variable. I agree that such name decoration can provide you type information without hovering mouse over identifier or navigating to type definition via a hot-key. This tiny benefit is outweighed by Hungarian notation disadvantages and other reasons mentioned below. Hungarian notation is not used in contemporary frameworks. C# has I
prefix (and this the only prefix in C#) for interfaces due to historical reasons (COM). In retrospect one of .NET architects (Brad Abrams) thinks it would have been better not using I
prefix. TypeScript is COM-legacy-free thereby it has no I
-prefix-for-interface rule.
Reason #2 I
-prefix violates encapsulation principle
Let's assume you get some black-box. You get some type reference that allows you to interact with that box. You should not care if it is an interface or a class. You just use its interface part. Demanding to know what is it (interface, specific implementation or abstract class) is a violation of encapsulation.
Example: let's assume you need to fix API 設計の神話: インターフェースは契約であるコード内で、たとえばICar
インターフェースを削除し、Car
代わりに基本クラスを使用します。次に、すべてのコンシューマーでこのような置き換えを実行する必要があります。I
-prefix により、コンシューマーはブラックボックス実装の詳細に暗黙的に依存するようになります。
理由3 不適切な名前付けから保護する
開発者は名前についてきちんと考えるのを怠ります。名前付けはコンピュータサイエンスにおける2つの難しいこと開発者がインターフェースを抽出する必要がある場合、クラス名に文字を追加するだけで簡単にI
インターフェース名が得られます。I
インターフェースのプレフィックスを許可しないと、開発者はインターフェースに適切な名前を選択するために頭を悩ませることになります。選択された名前はプレフィックスが異なるだけでなく、意図の違いを強調する必要があります。
抽象化の場合:ないICar
インターフェースと関連クラスを定義しないでくださいCar
。Car
は抽象化であり、契約に使用されるものでなければなりません。実装には、説明的で区別しやすい名前が必要です (例 ) SportsCar, SuvCar, HollowCar
。
良い例え:WpfeServerAutosuggestManager implements AutosuggestManager
、FileBasedAutosuggestManager implements AutosuggestManager
。
悪い例: AutosuggestManager implements IAutosuggestManager
.
理由4 適切に選ばれた名前はあなたを予防接種するAPI 設計の神話: インターフェースは契約である。
実務では、命名スキームを持つ別のインターフェースでクラスのインターフェース部分を無思慮に複製している人にたくさん会いましたCar implements ICar
。別のインターフェース型でクラスのインターフェース部分を複製しても、魔法のように抽象化に変換されるわけではありません。インターフェース部分が複製された状態でも、具体的な実装は得られます。抽象化がそれほど良くない場合は、インターフェース部分を複製しても、抽象化は改善されません。抽象化を抽出するのは大変な作業です。
注意: TSでは、クラスのモックや機能のオーバーロードに別のインターフェースは必要ありません。クラスのパブリックメンバーを記述する別のインターフェースを作成する代わりに、TypeScript ユーティリティ型たとえば、Required<T>
型のすべてのパブリック メンバーで構成される型を構築しますT
。
export class SecurityPrincipalStub implements Required<SecurityPrincipal> {
public isFeatureEnabled(entitlement: Entitlement): boolean {
return true;
}
public isWidgetEnabled(kind: string): boolean {
return true;
}
public areAdminToolsEnabled(): boolean {
return true;
}
}
パブリックメンバーを除いた型を構築したい場合は、次のようにします。省略と除外の組み合わせ。