我是从C#背景来到Typescript。
在C#中,如果我有一个名为BillingService
的类,并且它有调用结算服务的方法(可以进行付款,提供帐户余额等),那么对于我需要调用的代码部分那个类我将设置一个单独的程序集,其中定义了IBillingService
。
我的其余代码将使用依赖注入来获取IBillingService
,并且永远不会引用实际实现BillingService
的程序集。这有助于单元测试,松散耦合以及围绕数据隐藏的一些其他好处。
当我第一次开始使用TypeScript时,我一直这样做。但现在我想知道它是否有任何实际好处。明智地使用公共和私人似乎就足够了。
Typescript中没有单独的程序集。依赖注入可以注入实际的类,就像它已经实现了一个接口(至少Aurelia的依赖注入可以)。无论如何,JavaScript单元测试框架似乎都被Interfaces弄糊涂了。
所以,这是我的问题:
对于我上面概述的场景,TypeScript中的接口是否有用例?如果是,那是什么?
答案 0 :(得分:2)
与其他一些OO语言一样,在typescript中也不可能有多重继承,但是可以实现多个接口,这是接口适合的一个用例。
另一个原因是,如果您希望在不同的命名空间/模块中传播不同的实现,但您希望它们都能实现一组特定的方法:
namespace callbacks {
export interface Callback<T> {
getName(): string;
execute(): T;
}
}
namespace mynamespace1 {
export class Callback implements callbacks.Callback<string> {
public getName(): string {
return "mynamespace1.Callback";
}
public execute(): string {
return "executed";
}
}
}
namespace mynamespace2 {
export class Callback implements callbacks.Callback<boolean> {
public getName(): string {
return "mynamespace2.Callback";
}
public execute(): boolean {
return true;
}
}
}
但最好的理由(在我看来)是它允许你隐藏闭包内的实现类,这样就没有人可以直接创建它们,只能通过工厂函数或某些动作来创建它们:
namespace logging {
const httpLoggingEndpoint: URL = new URL(...);
const fileLoggingFilePath: string = "LOG_FILE_PATH";
export enum LoggerType {
Console,
Http,
File
}
export interface Logger {
log(message: string): void;
}
export function getLogger(type: LoggerType): Logger {
switch (type) {
case LoggerType.Console:
return new ConsoleLogger();
case LoggerType.Http:
return new HttpLogger();
case LoggerType.File:
return new FileLogger();
}
}
class ConsoleLogger implements Logger {
public log(message: string): void {
console.log(message);
}
}
class HttpLogger implements Logger {
public log(message: string): void {
// make a request to httpLogingEndpoint
}
}
class FileLogger implements Logger {
public log(message: string): void {
// log message to the file in fileLoggingFilePath
}
}
}
这样,没有人可以直接实例化记录器,因为没有实际的类被导出。
关于这个主题的另一点是,在打字稿类中可以被视为接口:
class Logger {
public log(message: string) {
console.log(message);
}
}
class HttpLogger implements Logger {
public log(message: string) {
// log using an http request
}
}
例如,用于mixins,所以在实践中我的前两个场景也可以用类来完成,虽然我的上一个例子不能用于类,因为那样你就可以实例化基类了通过这样做,绕过了不能直接调用不同构造函数的“安全机制”。