Typescript 与包作用域等效的类型脚本?

Typescript 与包作用域等效的类型脚本?,typescript,typescript2.0,Typescript,Typescript2.0,TypeScript中是否有一种方法允许一个文件访问另一个文件中的方法,但不使它们全局可访问 这种情况下的用例是拥有一个包含一些私有方法的大型类,这些私有方法是危险的,不应该公开以在代码库中的任何地方使用。我希望能够在另一个文件中编写访问它们的方法,以便在逻辑上对它们进行分组,而不必将它们全部放在一个巨大的类中 理想情况下,类似Java的PackageScope的东西会让我声明这两个文件可以访问彼此的危险方法,但不能访问其他任何人。是否有任何TypeScript语言功能允许此操作 例如: A级拥

TypeScript中是否有一种方法允许一个文件访问另一个文件中的方法,但不使它们全局可访问

这种情况下的用例是拥有一个包含一些私有方法的大型类,这些私有方法是危险的,不应该公开以在代码库中的任何地方使用。我希望能够在另一个文件中编写访问它们的方法,以便在逻辑上对它们进行分组,而不必将它们全部放在一个巨大的类中

理想情况下,类似Java的PackageScope的东西会让我声明这两个文件可以访问彼此的危险方法,但不能访问其他任何人。是否有任何TypeScript语言功能允许此操作

例如:

A级拥有从
d1
d100
的方法,这些方法都是危险的,不应该是全局可访问的

B类具有可供项目内公众安全使用的方法
s1
s100
。每个
s
方法在执行一些安全检查后调用
d
方法。B类需要访问所有
d
方法

类C想要调用任何
s
方法,并且应该能够调用,但不应该能够调用任何
d
方法

然而,据我所知,如果我导出任何
d
方法以便B可以调用它们,那么C也可以访问它们。如果这是Java,我会将A和B放在同一个包中,并使
d
方法包的作用域为

在TypeScript中似乎没有类似的功能,但是有没有什么东西可以模拟这样的目标:1)能够将功能分解成单独的文件,但2)限制谁可以调用这些方法


(是的,我知道一旦它被编译成Javascript,所有的赌注都没有了。目标是在编译时使用TypeScript作为静态检查器来验证契约。)

我将使用Rob提出的方法隐藏危险的方法:将类a与类B放在同一个文件中。导出类B,但不要导出类a。这样,类A只对类B可见。当然,作为替代方案,您可以创建一个巨大的类,但您在这条道路上犹豫是对的


但是,您应该注意:TypeScript编译为JavaScript,因此从JavaScript的角度来看,每一点不安全的代码都可以用于不必要的使用。

在TypeScript中没有直接的方法来强制执行这一点。根据我的经验,解决这类问题的最佳方法是通过清晰的文档和清晰的命名模式

如果有一个不熟练的或恶意的开发人员,他们将有许多方法来制造混乱,而编译器的限制将无法阻止他们。然而,所有具有合理技能和道德规范的开发人员都应该能够避免调用内部的、危险的方法

我的建议是生成某种命名约定。由于语言限制而公开的所有非API方法/属性/字段应具有相同的前缀或后缀

例如,我们团队的工作方式如下:

  • 所有非API公共方法/属性/字段的前缀都是
  • 所有非API公共类的后缀都是
    Internal
  • 所有非API模块都位于
    内部
    文件夹中。例如-
    src/models
    具有作为API的模型模块
    src/models/internal
    具有非API的模型模块
  • 所有非API类都有一条注释,将它们记录为非API类
  • 此外,我们还没有这样做,但正在考虑创建tslint规则来帮助实施这些规则。我们还没有走得太远,因为我们还没有任何开发人员意外地使用非API,但这仍然是一种可能性


    在我看来,适当的命名约定、适当的文档和适当的指导就足以解决这个问题,我同意这是Typescript语言的一个限制。

    Typescript中没有Java包范围等效,但有时确实需要它。这是我的解决方案:

    export class Foo {
    
        private doSomething(): void {
        //do something
        }
    }
    
    interface FooUnlocker {
    
       doSomething(): void;
    }
    
    const foo: Foo = new Foo();
    (<FooUnlocker><any>foo).doSomething();
    
    导出类Foo{
    私有doSomething():void{
    //做点什么
    }
    }
    接口解锁器{
    doSomething():无效;
    }
    const-foo:foo=new-foo();
    (foo).doSomething();
    
    优点-需要额外的约定,如_doSomething()等,代码是干净的,我们有编译检查

    缺点-我们需要同步Foo和founlocker


    节点,该FooUnlocker不会导出,因此它仅在模块内可见(如果使用ES6模块)。

    使用跨文件拆分的命名空间似乎可以很好地完成此任务:

    MyNamespace.ts
    文件中的内容一样:

    namespace MyNamespace {
        export interface Foo {}
    }
    
    同一名称空间加上另一个文件中的引用标记:

    /// <reference path="MyNamespace.ts" />
    namespace MyNamespace {
        export class Bar implements Foo {}
    }
    
    //
    名称空间MyNamespace{
    导出类栏实现Foo{}
    }
    
    为什么不把class
    A
    和class
    B
    放在同一个文件中,而不导出A呢?@Rob现在就是这样。两个类都在变大。最简单的重构就是将它们分成两个文件。丑陋的局部解决方法是,使用
    /**@internal**/
    将内容隐藏在
    .d.ts
    文件中。似乎还没有什么好方法可以做到这一点,尽管我在其他语言中见过一种风格,就是将私有内容放在一个名为
    mypkg/internal
    mypkg/private
    的“内部”模块中。虽然内部模块在技术上仍然是公开的,但对于库客户端来说,这是一个非常明确的“不要导入此!”信号。如果您不使用export标记一个类,并在模块内声明它,在使用它的类所在的同一个文件中,tsc将编译它。将类放在另一个文件中,它找不到它。我认为主要的问题是开发人员没有意识到他们正在到达他们不应该到达的地方。也许最简单的解决方案就是在