接口是否在Typescript中有用(从架构上讲)?

时间:2016-08-10 17:04:25

标签: typescript interface

我是从C#背景来到Typescript。

在C#中,如果我有一个名为BillingService的类,并且它有调用结算服务的方法(可以进行付款,提供帐户余额等),那么对于我需要调用的代码部分那个类我将设置一个单独的程序集,其中定义了IBillingService

我的其余代码将使用依赖注入来获取IBillingService,并且永远不会引用实际实现BillingService的程序集。这有助于单元测试,松散耦合以及围绕数据隐藏的一些其他好处。

当我第一次开始使用TypeScript时,我一直这样做。但现在我想知道它是否有任何实际好处。明智地使用公共和私人似乎就足够了。

Typescript中没有单独的程序集。依赖注入可以注入实际的类,就像它已经实现了一个接口(至少Aurelia的依赖注入可以)。无论如何,JavaScript单元测试框架似乎都被Interfaces弄糊涂了。

所以,这是我的问题:

对于我上面概述的场景,TypeScript中的接口是否有用例?如果是,那是什么?

1 个答案:

答案 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,所以在实践中我的前两个场景也可以用类来完成,虽然我的上一个例子不能用于类,因为那样你就可以实例化基类了通过这样做,绕过了不能直接调用不同构造函数的“安全机制”。