Flow: Import in declaration file breaks import in regular files

Created on 26 Jul 2016  路  6Comments  路  Source: facebook/flow

.flowconfig

[include]

[ignore]

[libs]
flow-libs/

[options]

flow-libs/lib.js

import {EventEmitter} from 'events';

declare class Foo extends EventEmitter {
  bar(): number;
}

test.js

/* @flow */
import {EventEmitter} from 'events';
const o = new Foo();

Flow gives an error:

test.js:2
  2: import {EventEmitter} from 'events';
             ^^^^^^^^^^^^ Named import from module `events`. This module has no named export called `EventEmitter`.


Found 1 error

Not great but changing flow-libs/lib.js to this makes Flow stop giving an error:

import {EventEmitter as _EventEmitter} from 'events';

declare class Foo extends _EventEmitter {
  bar(): number;
}

(I think I need to find a way to change my declaration files so that it doesn't leak globals like EventEmitter, but that's separate from this issue.)

Needs docs declarations

All 6 comments

I don't think Flow really supports imports in declaration files. Use events$EventEmitter to get more reliable behavior. cc @jeffmo

Yes, dependencies within Flow lib definitions are sort of missing right now. It would be great to improve it for this exact case.

However, as @avikchaudhuri mentioned, types within lib definitions are global across dependencies so you can reference stuff like events$EventEmitter directly. We have a nice naming scheme (moduleName$ObjectType) for this and won't break it on you (at least not until after we have a better solution).

@thejameskyle, @avikchaudhuri could you please provide an example of this ? Right now I have:
file definitions/foo.js:

// @flow
declare module 'foo' {
  declare type $Foo = { testFoo() : string };
  declare type $FooBaz = $Foo & baz$Baz;
}

file definitions/baz.js:

// @flow
declare module 'baz' {
  declare type $Baz = { testBaz() : number };
}

and index.js:

/* @flow */
import type { $Foo, $FooBaz } from 'foo';
import type { $Baz } from 'baz';

var baz : $Baz;

function test(fooBaz : $FooBaz) {
  const s : number = fooBaz.testFoo();
  const n : string = fooBaz.testBaz();
}

My .flowconfig is:

[libs]
definitions/foo.js
definitions/baz.js

When I run flow command I get following:

definitions/foo.js:4
  4:   declare type $FooBaz = $Foo & baz$Baz;
                                     ^^^^^^^ Library type error:
  4:   declare type $FooBaz = $Foo & baz$Baz;
                                     ^^^^^^^ identifier `baz$Baz`. Could not resolve name

flow version: 0.32.0

BTW: if I changing $Baz to Baz will not help.

The $ syntax is _just_ a convention for defining global type declerations. It doesn't do anything special. Here's an example based on yours:

file definitions/foo.js:

// types declared outside of a `module`-block are global.
// prefixed with `foo$` so that it doesn't clash with other definitions and it's clear where it's defined
declare type foo$Foo = { testFoo() : string };

declare module 'foo' {
  declare type LocalFooBaz = { a: boolean }
}

file index.js:

/* @flow */
// `foo$Foo` is always in scope
function test(fooBaz : foo$Foo) {
  return true
}

file other.js:

/* @flow */
import type { LocalFooBaz } from 'foo'
// Throws a type error
const x : LocalFooBaz = { y: 'invalid' }

Hey @Kriegslustig thanks a lot for that snippet, anyway this is .. hm .. far from perfect, cause basically this declaration becomes global... And instead of referencing that from module scope we just pick it as global... So I think there should be consensus about how to fix that to make import work better.

Hi @vaukalak! Sorry for the late answer. That is actually in the works https://github.com/flowtype/flow-typed/issues/16.

Was this page helpful?
0 / 5 - 0 ratings