与其他一些OO语言一样,在打字稿中也不可能有多重继承,但可以实现多个接口,这是接口适合的一种用例。
的另一个原因是,如果你想在不同的命名空间/模块传播不同的实现,但你希望它们都实现特定的一套方法:
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例如,所以我的前两个方案可以用类作为完成好吧,虽然我的最后一个例子不能和类一样好,因为那样你可以实例化基类,并绕过不能直接调用不同构造函数的“安全机制”。
接口对于“良好设计”和良好合同仍然很重要;如果使用得当,它们会在其余的程序构建过程中形成一个可靠的参考蓝图。他们还允许多份合同的清洁组合。然而,Typescript的[类型兼容性](https://www.typescriptlang.org/docs/handbook/type-compatibility.html)会将'必要使用'转移到一些.. – user2864740