【问题标题】:How does a Typescript API hide internal members?Typescript API 如何隐藏内部成员?
【发布时间】:2015-11-18 06:04:31
【问题描述】:

在 TS 中构建一个库以供 TS 和 JS 代码调用,并想知道人们如何隐藏内部方法和字段。 Java 具有包可见性来处理这个问题。在 TS 中缺少这一点,我看到了两个选项:

  1. 定义接口以仅公开某些成员。但这涉及复制定义和额外代码以将参数从接口转换为实现类型。

  2. 在内部成员上添加@private doc 评论。可能从生成的文档中排除此类。

注意:私有限定符不是解决方案,因为它只允许来自同一类的代码访问。我说的是需要访问同一个库中其他类的字段,但要阻止库的客户端访问。这就是 Java 的包访问所做的。

【问题讨论】:

  • 有一个 private 修饰符可以在 ES6/TypeScript classes 上使用。在编译时,TypeScript 在尝试访问 private 成员时会出现错误,但在运行时它们仍然可以访问。 (参见typescriptlang.org/Handbook#classes,尤其是“了解私有”部分)
  • 私有不是解决方案。我已经修改了问题以解释原因。
  • 好的,所以你并不真正想要private,而是更多的内部/包访问。由于 JavaScript 不是这样设计的,因此您想要做的是需要一些第三方 JavaScript 库来强制在运行时访问成员。 TypeScript 及其任何类型约束在运行时不存在。
  • 我通过将 API 的公共部分移动到根模块并将所有内部成员移动到子模块来解决这个问题 - 然后为声明 (.d.ts) 文件配置单独的构建,其中我只包括根模块。这样,子模块中的任何内容最终都会有效地在内部。 (反之亦然,如果您的子模块是公共的,请将您的内部成员移动到特定的子模块,并将其从您的声明构建中排除。)
  • 有一个内部修饰符的提议——我希望将来能看到:github.com/microsoft/TypeScript/issues/5228

标签: typescript


【解决方案1】:

从 TypeScript 3.1 开始,您可以使用 stripInternal 编译器选项。生成声明文件时,这将停止为具有 @internal JSDoc 注释的代码生成声明。

可以在tsconfig.json 文件中启用此编译器选项:

{
    "compilerOptions" : {
        ...
        "stripInternal": true
    }
}

例如,以下声明将被禁止:

//Class will not be visible
/** @internal */
export class MyHelperClass {

}

export class MyPublicClass {
    //Method will not be visible
    /** @internal */ 
    helperMethod() {}
}

// Binding will not be visible
/** @internal */
export const MyValue = 5;

但是,这不会影响看到 *.ts 源文件的代码,例如您自己的代码。

如果您将包作为*.js*.d.ts 文件的混合分发,就像大多数 NPM 包一样,这将有效地将成员隐藏在包外的代码中。但是,如果您将代码分发为 *.ts 文件,它对您没有帮助。

【讨论】:

【解决方案2】:
  • 您可以使用private 修饰符关键字将字段和函数标记为私有。
  • 您可以使用命名约定,例如以下划线开始所有私有。
  • 如果不应公开类,您还可以使用命名约定(带有“内部”或其他内容的前缀。您还可以在(类)文档中说明该类不打算在框架之外的任何地方使用。

请注意,由于基于原型的语言,最终 JavaScript 中的所有内容都是相当公开的。也没有实际的命名空间。所以也许你不应该太担心。好的文档总是有帮助的。


作为旁注,知道还有其他很棒的转译器(如 TypeScript)可能会很有趣。例如,Haxe 更优雅地解决了这个问题,因为它们更面向 OOP 的语言设计,您可以在访问修饰符之上使用元数据授予和请求访问权限。您可能会发现这来自 Java 更方便。尽管如此,由于 JavaScript,最终一切都会公开。

【讨论】:

    【解决方案3】:

    从 1.3 开始,protected 可用作访问说明符。这是您(和我的)担心的问题之一。

    至于限制其他成员对某些库的可见性,至少在涉及 TypeScript 编译器的情况下,您可以创建不同版本的声明文件。

    假设您使用--declaration 开关编译一个文件,生成一个.d.ts,该文件如下所示:

    class Something {
        // ...
        public internal_use_only: someType;
        // ...
    }
    

    要生成更严格的声明文件,只需将其复制到另一个文件并删除包含internal_use_only 的行。

    如果您希望在编译/测试周期内自动执行此操作,您可以使用 [ 任务运行器 |项目构建实用程序] 脚本,它使用--declaration 开关和然后 一个文本处理实用程序,如grep(在Linux 或Cygwin 中找到,它为Windows 提供一些Un*x 命令和 shell 环境)。只删除有问题的行的 grep 命令调用如下所示:

    cat something.d.ts | grep -v \\binternal_use_only\\b > moreRestrictiveSomething.d.ts

    其他 shell 也有类似的命令,例如 Windows/CMD 中的 findstr,它也适用于 Regular Expressions

    【讨论】:

    • 这是一个有趣的想法 - 将 .d.ts 文件用作接口定义。根据没有@private doc 注释生成它。它会比 grep 更复杂,因为内部成员是多行表达式,包括 cmets,但可以使用解析器。
    猜你喜欢
    • 2020-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-14
    • 2010-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多