Typescript Equivalent to package scope?

Is there a way in TypeScript to allow one file to access methods in another file, but not make them globally available?

A use case for this is having a large class with some private methods, which are dangerous and should not be publicly exposed to potential use anywhere in the code base. I want to be able to write methods that refer to them in another file to allow them to be grouped logically, without all of them being in one giant class.

Ideally, something like a Java package scope allows me to declare that the two files can access each other's dangerous methods, but not anyone else. Is there any TypeScript language feature that allows this?

Example:

Class A has methods d1

through d100

which are dangerous and should not be globally accessible.

Class B has methods s1

through s100

that are safe for public consumption within the project. Each method s

calls the method d

after performing a security check. Class B must have access to all methods d

.

Class C wants to call any of the methods s

and should be able to, but should not be able to call any of the methods d

.

However, as far as I understand Typescript, if I export any of the methods d

so that B can call them, they are then also available to C. If it were Java, I would put A and B in the same package and inject a scope method package d

.

There seems to be no parallel in Typescript to this, but is there something that mimics the goals: 1) being able to split functionality to separate files, but 2) limiting who can call methods?

(Yes, I know, once it's compiled to Javascript, all bets are off. The goal is to just use TypeScript as a static checker to check contracts at compile time.)

+6


source to share


3 answers


There is no direct way to enforce this in Typescript. In my experience, the best way to solve this problem is with clear documentation and clear naming patterns.

If you have an unqualified or malicious dev, they will have multiple ways to create chaos and compiler constraints, they will stop little. However, all reasonably qualified and ethical developers should be able to avoid invoking internal, dangerous methods.

My recommendation would be to create some kind of naming convention. All non-API methods / properties / fields that are publicly available due to language restrictions must have the same prefix or suffix.

For example, the way our team works is as follows:



  • All non-API public methods / properties / fields are prefixed _

    .
  • All public non-API classes are flagged Internal

    .
  • All non-API modules are in the folder Internal

    . For example, it src/models

    has modules that are API. src/models/internal

    has model modules that are not API.
  • All non-API classes have a comment that documents them as non-API.

Also, we haven't done so yet, but are considering creating tslint rules to enforce those rules. We didn't get too far down this path as we didn't have any developers accidentally using non-APIs, but it's still possible.

In my opinion, the correct naming convention, correct document and proper mentoring are enough to solve this problem, that I agree that this is a limitation of the Typescript language.

+5


source


I would hide the dangerous methods using the approach Rob suggested: put class A in the same file as class B. Export class B, but don't export class A. That way class A is only available for class B Of course, alternatively you could create a giant class, but you are right to hesitate along the way ...



You should be careful: TypeScript compiles to JavaScript, so every bit of unsafe code is available for unwanted use from a JavaScript perspective.

0


source


There is no TypeScript equivalent to a Java package scope, but sometimes it is really necessary. This is my decision:

export class Foo {

    private doSomething(): void {
    //do something
    }
}

interface FooUnlocker {

   doSomething(): void;
}

const foo: Foo = new Foo();
(<FooUnlocker><any>foo).doSomething();

      

Benefits - there is a need for additional conventions like _doSomething () etc., the code is clean and we have a compile check.

Disadvantages - we need to keep Foo and FooUnlocker in sync.

The node that FooUnlocker is not exported, so it is only visible inside the module (if using ES6 modules).

0


source







All Articles