Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does a Typescript API hide internal members?

Tags:

typescript

Building a library in TS to be called by TS and JS code and wondering how people hide internal methods and fields. Java has package visibility to handle this. Lacking that in TS, I see two options:

  1. Define interfaces to only expose certain members. But this involves duplicating the definitions and extra code to cast arguments from interface to implementation types.

  2. Put an @private doc comment on the internal members. Possibly exclude such from generated docs.

Note: the private qualifier is NOT a solution, as it only allows code from the same class access. I am talking about the need to access fields from other classes in the same library, but preventing access from clients of the library. That is what Java's package access does.

like image 578
Jonathan Edwards Avatar asked Aug 24 '15 17:08

Jonathan Edwards


2 Answers

Since TypeScript 3.1, you can use the stripInternal compiler option. When generating declaration files, this stops declarations being generated for code that has the @internal JSDoc annotation.

This compiler option can be enabled in the tsconfig.json file:

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

For example, the following declarations will be suppressed:

//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;

However, this will have no effect on code that sees the *.ts source files, such as your own code.

If you distribute your package as a mix of *.js and *.d.ts files, like most NPM packages, this will effectively hide the member from code outside your package. But if you distribute the code as *.ts files, it won’t help you.

like image 163
GregRos Avatar answered Oct 27 '22 17:10

GregRos


  • You can mark fields and functions as private using the private modifier keyword.
  • You can use a naming convention, like start all privates with an underscore.
  • If the classes should not be exposed you can also use naming convention (prefix with "Internal" or something. You can also put in the (class) documentation that the class is not intended to be used anywhere outside the framework.

Note that in the end everything in JavaScript is quite public because of the prototyped based language. There are also no actual namespaces. So maybe you should not worry too much. Good documentation always helps.


As a sidenote it might be interesting to know that there are great other transpilers like TypeScript. Haxe for example solves this problem a bit more elegant because of their more OOP oriented language design, where you can grant and request access using metadata on top of the access modifiers. You might find this more convenient coming from Java. Still, in the end everything will be public because of JavaScript.

like image 24
Mark Knol Avatar answered Oct 27 '22 19:10

Mark Knol