Feature Request: Modules Packages #35688
Labels
Out of Scope
This idea sits outside of the TypeScript language design constraints
Suggestion
An idea for TypeScript
Search Terms
package, modules encapsulation, modules union, modularization, modules categorization, module access level
Suggestion
Provide a mechanism for explicit modularization with strict boundaries and access levels within a single project. This suggestion is only about type - checking and won't affect runtime behaviour.
Applications and teams grow really fast nowadays, so a convenient way of encapsulation is required. The main point is to categorize application modules and provide access protection for them. Currently, we have access protection control on a single module (file) level using
export
modifier that sets the access level globally in the whole project. But it's a common situation when module/package can consist of more than one file, so to call some internal implementations from another file, we need to export them (make them globally accessible) breaking access hierarchy.Current approaches and workarounds:
Namespaces
Namespaces can't be used to solve this problem, as primarily were developed with the global context in mind. But for now, almost everyone and everything (frameworks, build tools, environments, etc.) focused on modules. Due to current namespaces behaviour, it's more about types declarations. (More info)
In my personal opinion, even modification of current namespaces behaviour won't solve the problem, as actual modules merging is not TypeScript responsibility. By the way, such change will also affect runtime behaviour that isn't really good. And another thing is syntax. Looks like TypeScript namespaces were heavily inspired by C# namespaces. For TypeScript/JavaScript, It's not really good to have structures that wrap top-level (file) code, as it kills top-level at all.
Project References
Project References provide some kind of module categorization and can be as alternative for mono-repos(in some way). It's a good approach for relatively large units, but not really good for small packages consisting of only 2-3 modules (files). By the way, Project References can't solve access protection problems, as all referenced modules will be public by default. Also, Project References affects build behaviour, so frameworks and tools must adjust their processes.
Index File
The most popular workaround is exporting package members using
index.ts
file. Such approach categorizes modules within a single project, but it's more like a visual fix. Access to internal members still opened.Use Cases
Modules categorization
Application components can be categorized by their type. For example -
models
,views
,controllers
in MVC. It will provide more strict architectural boundaries.Internal implementations
It's a common situation when a single application component consists of several internal application components, that don't need to be publicly accessible.
The best example is Atomic Design in React Apps. Imagine that we are building some complex React component, that aggregates smaller components inside and adds some new logic (functions, etc.). Due to component complexity, we can't fit everything into a single file (it's semantically incorrect), so we decompose it in small modules with different responsibilities. But we just need the main component publicly accessible. Other internal things will simply clog the project with publicly accessible units that won't be used anywhere except for internal implementation.
Private Access Level
Another thing is primarily about access boundaries. For example, a class with a private constructor and static factory methods. Or private inner class that used only for internal logic. Sometimes developers don't want to provide full (uncontrolled) access to all units but want to provide only a few controlled entry points. Same thing with modules. Several modules can depend on another module that used only within these modules and doesn't need to be publicly accessible, so it's semantically private. The main points - are granular access level control within project and encapsulation.
Performance optimization
Based on packages resolution, TypeScript Language Services can skip a lot of work and provide type-checking,modules resolution, etc. only within package/global boundaries.
Examples
package
andusing
keywords can be used for this functionality.That's enough to have only 2 statements in simplified version:
package <identifier>;
- inclue module in packageusing <identifier, identifier, ...>;
- reference packge(s) from global context or from another packageFor example:
Defining that module is part of package
Referencing package from global package/context module
Referencing package from of another package module
Behaviour description
In this case, we will have entry-point files to packages that are part of global context and used only for package referencing and exporting package members.
foo
function can be imported from./bar/index.ts
, butbaz
function can't be imported directly frombar/some.ts
, as package referencing is not transitive. Referenced packages can be accessed only in referencing module scopeAccess level modifiers
Only one access level modifier is needed -
protected
. So export declaration must be modified in the following way -export protected? Statement/Declaration
. (Added optional modifierprotected
). Protected exports can be used within package, and can't be imported anywhere outside package.Checklist
My suggestion meets these guidelines:
The text was updated successfully, but these errors were encountered: