Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript Equivalent of package scope?

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

The use case for this is having a large class with some private methods that are dangerous and shouldn't be publicly exposed to be potentially used anywhere in the codebase. I want to be able to write the methods that access them in another file to allow logically grouping them without them all being in a single giant class.

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

Example:

Class A has methods d1 through d100 that are all dangerous and shouldn't be globally accessible.

Class B has methods s1 through s100 that are safe for public consumption within the project. Each s method calls through to a d method after doing some safety checking. Class B needs to have access to all of the d methods.

Class C wants to call any of the s methods and should be able to, but shouldn't be able to call any of the d methods.

However, as I understand Typescript, if I export any of the d methods so that B can call them, they are then accessible to C as well. If this were Java, I would put A and B in the same package and make the d methods package scope.

There doesn't seem to be any parallel to this in TypeScript, but is there anything that simulates the goals of 1) being able to break the functionality in to separate files but 2) limiting who can call the methods?

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

like image 633
bsberry Avatar asked May 15 '17 05:05

bsberry


2 Answers

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

If there is a unskilled or malicious dev, they will have any number of ways to create havoc and compiler limitations will do little to stop them. However, all reasonably skilled and ethical developers should be able to avoid calling internal, dangerous methods.

My recommendation would be to generate some sort of naming convention. All non-API methods/properties/fields that are public due to language limitations should have the same prefix or suffix.

For example, the way that our team works is the following:

  1. All non-API public methods/properties/fields are prefixed with _.
  2. All non-API public classes are suffixed with Internal.
  3. All non-API modules are in an internal folder. Eg- src/models has the models modules that are API. src/models/internal has the models modules that are not API.
  4. All non-API classes have a comment that documents them as non-API.

Also, we have not done this yet, but are considering creating tslint rules to help enforce these rules. We haven't gone too far down this path yet since we haven't had any devs accidentally using non-API, but this is still a possibility.

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

like image 196
Andrew Eisenberg Avatar answered Oct 10 '22 00:10

Andrew Eisenberg


Using a namespace split across files seems like it would accomplish this nicely:
https://www.typescriptlang.org/docs/handbook/namespaces.html#splitting-across-files

As with this in MyNamespace.ts file:

namespace MyNamespace {
    export interface Foo {}
}

And the same namespace plus a reference tag in another file:

/// <reference path="MyNamespace.ts" />
namespace MyNamespace {
    export class Bar implements Foo {}
}
like image 42
karlgold Avatar answered Oct 10 '22 00:10

karlgold