facebook / flow

Adds static typing to JavaScript to improve developer productivity and code quality.
https://flow.org/
MIT License
22.08k stars 1.85k forks source link

Request: `import type *` (wildcard type-imports) #6726

Open wchargin opened 6 years ago

wchargin commented 6 years ago

One can write import * as D from "./dep", and then use D.SomeType throughout the rest of the module, as a convenient way to import many types while preserving namespacing.

However, this has runtime effects, and forces the contents of the dependency module to be bundled with the dependent module, even though they may never be used. Currently, we must explode the wildcard import to import type {Lots, Of, Types} from "./dep" in order to reduce the bundle size; in addition to being inconvenient, this loses the benefits of namespacing.

A form import type * as D from "./dep" with the evident semantics would be a great, simple addition.

mgtitimoli commented 6 years ago

I would love to have this, as right now I'm overcoming this issue by prepending all the types a module exports with its name to avoid collisions, and in addition to this, having to import them one by one as I want to keep types vs non-types import statements separately.

jcready commented 6 years ago

How would this work for class instance types?

// dep.js
export class Foo {}
export type Bar = {}
// index.js
import type * as D from "./dep"

// Can I do this?
const foo = new D.Foo()
wchargin commented 6 years ago

How would this work for class instance types?

[…]

// Can I do this?
const foo = new D.Foo()

It would work in the same way that import type already does. You cannot do that, because you cannot do the following:

index.js

// @flow
import type { Foo as DFoo } from "./dep";

// This fails:
const foo = new DFoo();
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ index.js:5:17

Cannot reference type DFoo [1] from a value position.

 [1] 2│ import type { Foo as DFoo } from "./dep";
     3│
     4│ // Can I do this?
     5│ const foo = new DFoo();
     6│

Found 1 error
wchargin commented 6 years ago

@mgtitimoli: Instead of prepending all the exports with module names, you could consider aliasing them at import time:

// @flow
import type { Bat as BaseballBat } from "./baseball";
import type { Bat as AnimalBat } from "./chiroptera";

This has preserves the simplicity of the module interfaces, and admits an easy upgrade path in the case that import type * is introduced. It also permits greater locality of reasoning: a module exporting a member doesn’t need to consider all other modules that could possibly exist; a module importing a member needs only consider the other things that it imports, which are lexically immediately adjacent.

(Edit: Of course, this is just an improvement to a workaround, not an actual fix. :-) )

mgtitimoli commented 6 years ago

I was initially doing that @wchargin, and I agree it's nice when you are importing just one type, or from just one place, but it starts to become a bit noisy as soon as you import more than one type and it gets even worse if you do that from multiple sources...

wchargin commented 6 years ago

Yep, fair enough.

STRML commented 3 years ago

Now that you cannot import * as React from 'react' in an interface file due to the new rules in 0.143.0, using React is a fair bit more obnoxious as you need to import every single member individually.