Open RebeccaStevens opened 4 years ago
I like this approach! I think it would solve the most common use cases enumerated in #35554, #5228, #321, etc - that of needing a level between "public" and "private" (other than "protected" which is class-specific) to provide access to internals in a controlled way for the purpose of unit testing or to classes which do not extend the class itself.
Currently, there is no "protected" equivalent for modules, so people use kludges like prefixing an underscore to the name to indicate that it's "internal" and shouldn't be used outside of that file and its unit tests. Having an official way to do this which is supported in the language would be outstanding.
For example, the file Diagram.tsx
:
export function Diagram(props: DiagramProps) {
return <>
<_Header>My Floorplan</_Header>
{props.rooms.map((r) => <_Room path={r.path}>{r.name}</_Room>)}
<_Legend />
</>;
}
export function _Header(props: HeaderProps) { ... }
export function _Room(props: HeaderProps) { ... }
export function _Legend() { ... }
would become:
export function Diagram(props: DiagramProps) {
return <>
<Header>My Floorplan</Header>
{props.rooms.map((r) => <Room path={r.path}>{r.name}</Room>)}
<Legend />
</>;
}
private export function Header(props: HeaderProps) { ... }
private function Room(props: HeaderProps) { ... }
private function Legend() { ... }
This would allow Diagram.test.tsx
in the same directory access to the 3 private exports so it can fully mock them, unit test them, etc while preventing access outside of this directory.
Another approach to solve this issue would be Conditional Compilation - https://github.com/microsoft/TypeScript/issues/3538#issuecomment-893566580 - but that's been sitting open for 6 years without any real movement on it...
May I propose some clearer (IMHO) keywords:
folder export const foo = "visible in the same folder";
tree export const bar = "visible in the same folder and its recursive children";
export const baz = "same as before";
We might also have something like:
export class MyClass {
file public const foo = "visible in the same file";
}
The file public
makes class members visible to the code outside of the class but in the same file. This would be great for observable-driven React components, as described in https://github.com/microsoft/TypeScript/issues/35554#issuecomment-979737464.
We might even have folder public
and tree public
.
All of these could be useful when we need to make the visibility of the member more limited compared to the visibility of the class.
I also upvoted for this feature. I'm annoyed by the fact that libraries use folder index files and when you're importing types, it may be confusing which path to import them from. And other developers may import the same thing from a different path which leads to unclean code.
I would suggest another modifier: hidden
or in the scope of your modifiers public hidden
. This would allow the import of the type, but you would have to know that it exists. Because what I'm mostly annoyed at is that libraries for instance may have this structure:
├── components
│ ├── componentOne
│ │ ├── ComponentOne.tsx
│ │ └── ComponentOne.theme.ts
: :
│ └── componentN
│ ├── ComponentN.tsx
│ └── ComponentN.theme.ts
└── index.ts
All components could have public hidden exports of the components themselves and /components/index.ts
would re-export them with normal public export. This would help code hinting/intellisense tools to filter out hidden import paths or at least put the hidden ones at the end of the possible selection to use as an import path. The latter is IMHO a better approach because there may be types that one would want to export as hidden, so it should not be used but for the very uncommon occasion it could. It would be possible to import it, but being a hidden export would automatically signal that this is some functionality that should used with caution.
There's another issue #41425 discussing the same problem.
FWIW, it seems like Microsoft has also run into this problem, and has made their own solution using "packlets". I agree that it'd be nice to have something like this be more standard. However, I do wonder whether it's something that should be developed in concert with other players in the JS ecosystem, rather than just addressing it in TS only through custom syntax.
Love this idea, might be cool if you could use a type
modifier on this to so that way you could make a type signature public/protected and keep the code private.
Search Terms
export access modifiers public protected private
Related: #321
Suggestion
Allow adding
public
,protected
andprivate
access modifiers to export statements. This would limit where the data can be imported from.Access Modifiers
private
Other file in the same directory scope have access to the export.
protected
Other file in the same directory scope or a nested scope have access to the export.
public
(default)Current behavior - Can be access from anywhere.
Use Cases
Most useful for large projects - allows modules to limit where things they expose are used.
Examples
Given the following director structure:
Note: If using
import * as X from ...
,X
's type simply wouldn't include things it doesn't have access to.Checklist
My suggestion meets these guidelines: