Additional features to `import * as Object from 'module'`

Hey, my first time here, sorry in advance if I've made some error about the process of opening a proposal.
Just want to discuss the import * as Object from 'module' feature in ECMAScript.

Why there is no way to import only some definitions? sometimes where do we use some utility packages like lodash or ramda that exposes utility functions is a common practice to rename it or wrap it to make it recognizable at first glance from where it comes from.

Today if we want to import some methods from another module but having it "wrapped" inside an object we need to do:

import { pathOr, mergeRight } from 'ramda';
const R = { pathOr, mergeRight };

Why we can't do:

import { pathOr, mergeRight } as R from 'ramda';
2 Likes

Why is it that you only want to import selected items instead of everything? The whole module will get loaded anyways. Unless, is this for tree-shaking purposes - to help a tree-shaker know that you only really care about a couple of definitions?

1 Like

Treeshaking only provides a benefit when you import more than you need - which can only happen when you export more than you should.

If only "some" of a module might be needed at a time, imo it belongs in a different module - ie, in another file. Deep imports obviate the need for treeshaking, and make for much smaller application footprints and bundle sizes.

You already can do

import * as R from 'ramda';

and then refer to only the R.pathOr and R.mergeRight functions that you need. This behaves just the same your first snippet, but with less syntax.
Or do you want to pass the R object as an argument to something, and restrict what methods should be available on that object? That's a rather unusual use case.

Im curious if there are other mainstream prog languages that offer this style of module import.
Off the top of my head other languages follow the same pattern of either importing everything or specific names which are either directly available, or can be renamed to avoid conflict.

1 Like

Yep exactly, with that import, I'm telling: I'm using only those definitions. Like the import already implemented in the ecmascript specification.

I know it’s just a syntactic sugar thing, but as said in other comments could be interesting if we have similar methods instead of renaming every single method we have the possibility to wrap it to avoid conflicts

many modern tools can tree shake individual named exports even when using import * as Lib from 'lib'.

2 Likes

Whom are you telling, and for what purpose?

Notice that the current import syntax only tells the engine which aliases/bindings to set up in the module scope, not which of them you're going to use.

i like it.
i hope it coming.

@chensuiyi.com - do you think you could explain why you would find a feature like this valuable? I don't think it was ever made clear in the thread thus far why it's valuable to import specific methods, grouped together into an object, instead of just importing the whole module as an object.

1 Like

@theScottyJam namespace imports often “prevent inefficient tree shaking and increase bundle size”

in a perfect world, this feature would work nearly identically to the below:

// ❌ Avoid namespace imports, it can prevent efficient tree shaking and increase bundle size.
// import * as v from "valibot";

import { object, optional, parse, string } as v from "valibot";
v.object // ✅

/* instead of... */

import { object, optional, parse, string } from "valibot";
object // ⚠️ unclear name, better in namespace

/* suboptimal alternative */
import { object, optional, parse, string } from "valibot";
const v = { object, optional, parse, string };
v.object // 🤷

Independently came up with this idea, and after reading the new feature proposal process doc and searching the forum, seems like this is the most well defined thread on the topic. The op doesn't give the feature a name so I'll just call it Named Subset Import for my response. And what seems to be holding it back is a list of benefits that would set this apart from deep imports, or * imports.

Here are the benefits I see:

  1. Simplified pollution prevention when combining modules
    • Good syntax reduces coupling and cognitive load. At the moment the only tool we have today which accomplishes that is barrel files/* imports.
    • E.g. suppose I have written two modules for working with two distinct types of objects, a "BigInt" math library and a "ImaginaryNumber" math library. Both modules should have an add method in them. But what should I call the method? If these truly are well scoped and targeted modules, add is the only real name that makes sense. Not addBigInt or addImaginary because in the context of just the BigInt module, there is no other add method that I could possibly need to differentiate from. But if I'm writing an app that makes use of both modules that means I can't import both methods without renaming them. Fine for 2 methods, but what about divide, multiply, etc. etc.? And I need to rename these imports to differentiate them in every module in my app?
    • There are 2 solutions today I have seen, both are not great
      • namespacing all methods
        • See this real world open source application - Liftosaur. The author simply said enough of the troubles with name collisions and tree shaking failures and instead prefixed every method in every file.
        • Some languages really lean heavily into this namespacing of everything. E.g. Java and C#, but that's not really a practice that javascript has leaned into, and so it doesn't have the syntax to make namespacing everything ergonomic to work with.
      • barrel files
        • As pointed out by Delegate ljharb in several places on the forum, barrel files are considered poor practice, lazy, or niche. Instead the preference is to do deep imports on small self contained modules. Taken to it's logical conclusion, that puts pressure to break up files more and more, which then creates more and more import statements, and more and more duplication of named import renames. Exacerbating the frustrations that make barrel files attractive despite their flaws.
  2. Tree shaking even when dynamic access is involved, or static analysis fails
    • Suppose a module exports 100 methods, and you wish to dynamically call 1 of 10 of those methods. Tree shaking would not be possible because static analysis cannot determine the subset of 10 methods you've narrowed down to. With a Named Subset Import you would be able to import just those methods and dynamically make use of them. Tree shaking doesn't need to even check how the import is used - it knows that 90 of those methods will never and can never be called.
  3. Reduced cognitive load via chunking, scope reduction
    • Chunking of information is known to reduce effort it takes to recall information. Modern IDE's aid recall by bringing up relevant identifiers when you type, but they are limited by the identifiers present. If I have needed to rename an imported identifier multiple times to avoid namespace collision I'm going to have difficulty recalling which name was the name used in the context I am in. By using a named subset, I don't rename methods, I chunk them. So if I import {add} as BigInt from "./maths/bigint" and also import {add} as Imaginary from "./maths/imaginary" then I can type BigInt. to get suggested all the methods which I've imported, and only the methods that I've imported.
1 Like

import { a } as lib from "lib"; was discussed at TC39 this week as part of GitHub - tc39/proposal-deferred-reexports · GitHub.

Slides: 2026-05 - export defer status update - Google Slides

2 Likes

If this existed, I probably would have used it in code I wrote today.

1 Like

From the slides looks like the working name of the feature is Filtered Namespace Imports. Just wanted to point that out in case me calling it something else in my first response there ends up being confusing later down the line.