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

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