我通读了 编码指南
我觉得这句话很令人费解:
不要使用“ I”作为接口名称的前缀
我的意思是,没有“ I”开头的词,这样的事情就说不通了
class Engine implements IEngine
我漏掉了什么明显的东西吗?
另一件我不太明白的事是:
课程 为了保持一致性,不要在核心编译器管道中使用类。使用 函数闭包。
课程
为了保持一致性,不要在核心编译器管道中使用类。使用 函数闭包。
这是否说明我根本不应该使用类?
希望有人能为我澄清一下:)
关于你提到的链接的澄清:
这是关于 TypeScript 代码样式的文档,而不是关于如何实现项目的样式指南。
如果使用 I前缀对您和您的团队有意义,那么使用它(我就是这样做的)。
I
如果没有,那么可以使用带有 SomeThingImpl(实现)的 SomeThing(接口)的 Java 样式。
SomeThingImpl
SomeThing
当一个团队/公司发布一个框架/编译器/工具集时,他们已经有了一些经验,一套最佳实践。他们把它作为指导方针。指南是 建议。如果你不喜欢,你可以忽略它们。 编译器仍将编译 你的代码。 尽管在罗马的时候... ..。
这就是为什么 TypeScript 团队建议不要使用 I前缀接口的原因。
来自 I-prefix-for-interface 支持者的主要观点是,前缀有助于立即确定(偷看) type 是否是一个接口。声明前缀有助于立即垂头丧气(窥视)是呼吁 I0。前缀 I表示接口名称,C表示类,A表示抽象类,s表示字符串变量,c表示常量变量,i表示整数变量。我同意这种名称修饰可以为您提供类型信息,而不必将鼠标停留在标识符上或通过热键导航到类型定义。这一微小的好处被 I0的缺点和下面提到的其他原因所超过。匈牙利命名法在当代框架中并不使用。由于历史原因(COM) ,C # 对接口有 I前缀(这是 C # 中唯一的前缀)。回想起来。NET 架构师(Brad Abrams)认为 I2会更好。TypeScript 是没有 COM 遗留的,因此它没有 I前缀换接口规则。
C
A
s
c
i
假设你有黑匣子。您可以获得一些类型引用,以便与该框进行交互。您不应该关心它是一个接口还是一个类。你只需要使用它的接口部分。要求知道它是什么(接口、特定实现或抽象类)违反了封装。
示例: 假设您需要在代码中修复 API 设计神话: 接口作为契约,例如,删除 ICar接口,而使用 Car基类。然后您需要在所有消费者中执行这样的替换。I-前缀导致消费者对黑盒实现细节的隐式依赖。
ICar
Car
开发人员懒得正确考虑名称。命名是 计算机科学中的两大难题之一。当开发人员需要提取一个接口时,只需将字母 I添加到类名称中,就可以得到一个接口名称。不允许接口使用 I前缀迫使开发人员不得不为接口选择合适的名称。所选名字不仅要有前缀的不同,而且要强调意图的不同。
抽象情况: 您应该 没有不定义 ICar接口和相关的 Car类。Car是一个抽象概念,它应该是一个用于合同的概念。实现应该具有描述性的、与众不同的名称,例如 SportsCar, SuvCar, HollowCar。
SportsCar, SuvCar, HollowCar
好例子: WpfeServerAutosuggestManager implements AutosuggestManager,FileBasedAutosuggestManager implements AutosuggestManager。
WpfeServerAutosuggestManager implements AutosuggestManager
FileBasedAutosuggestManager implements AutosuggestManager
不好的例子: AutosuggestManager implements IAutosuggestManager。
AutosuggestManager implements IAutosuggestManager
在我的实践中,我遇到过许多人,他们不假思索地将类的接口部分复制到具有 Car implements ICar命名方案的单独接口中。在单独的接口类型中复制类的接口部分并不能神奇地将其转换为抽象。您仍然可以得到具体的实现,但是具有重复的接口部分。如果你的抽象不是那么好,复制接口部分将无论如何不会改善它。提取抽象是一项艰巨的工作。
Car implements ICar
注意: 在 TS 中,您不需要单独的接口来模拟类或重载功能。 您可以使用 实用程序类型而不是创建一个单独的接口来描述类的公共成员。例如,Required<T>构造一个类型,该类型由 T类型的所有公共成员组成。
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; } }
如果您想构造一个不包含某些公共成员的类型,那么可以使用 省略和排除的组合。
作为接口的类型是一个实现细节。实现细节应该隐藏在 API: s 中。这就是为什么你应该避免 I。
你应该避免两种 prefix 还有 suffix。这两种都是错误的:
prefix
suffix
CarInterface
您应该做的是在 API 中显示一个漂亮的名称,并在实现中隐藏实现细节。这就是为什么我建议:
CarImpl
我觉得 @ stanislav-berkov是对观察员问题的一个很好的回答。我只想分享我的两分钱,并补充说,最终取决于你的团队/部门/公司/无论什么,达成共识,并制定自己的规则/指导方针。
只要有可能和需要,坚持标准和/或惯例是一种好的做法,它使事情更容易理解。另一方面,我确实愿意认为我们仍然可以自由选择编写代码的方式。
从情感的角度思考,我们编写代码的方式,或者我们的编码风格,反映了我们的个性,在某些情况下甚至是我们的情绪。这就是我们人类遵守规则的原因,而不仅仅是编码机器遵守规则。我相信编码不仅仅是一个工业化的过程,而是一门手艺。
我个人非常喜欢通过添加-able 后缀把名词变成形容词的想法。听起来很不合时宜,但我喜欢!
interface Walletable { inPocket:boolean cash:number } export class Wallet implements Walletable { //... }
}
我尝试使用与其他答案类似的模式,但是导出一个函数,将具体类实例化为接口类型,如下所示:
export interface Engine { rpm: number; } class EngineImpl implements Engine { constructor() { this.rpm = 0; } } export const createEngine = (): Engine => new EngineImpl();
在这种情况下,具体的实现永远不会被导出。
我确实喜欢添加一个 Props后缀。
Props
interface FormProps { some: string; } const Form:VFC<FormProps> = (props) => { ... }
在打字稿文档中建议的指导方针并不是针对那些使用打字稿的人,而是针对那些为打字稿项目做出贡献的人。如果您在阅读页面的细节时,它清楚地定义了谁应该使用该指南。这里有一个指导方针的链接。 打字指南
总而言之,作为一个开发人员,您可以按照自己认为合适的方式命名接口。