Angular-cli: Warnings when using an exported interface in a class

Created on 9 Sep 2016  ·  140Comments  ·  Source: angular/angular-cli

1. OS

Arch Linux

Linux maistho-laptop 4.7.2-1-ARCH #1 SMP PREEMPT Sat Aug 20 23:02:56 CEST 2016 x86_64 GNU/Linux

2. Versions

angular-cli: 1.0.0-beta.11-webpack.8
node: 6.5.0
os: linux x64

3. Repro steps

I started a new repository, and added a new empty service, with an exported interface.

Complete changes, and a repo to pull and see the issue, can be found here:

https://github.com/Maistho/angular-cli-input-issue/commit/e5c483081bfd7af3dafd0db074179b3090668e27

After running ng build, I get two warnings in the Terminal

4. The log given by the failure

Hash: 354e709ba2cf588db59a                                                                                                                                                                                          
Version: webpack 2.1.0-beta.21
Time: 11161ms
            Asset       Size  Chunks             Chunk Names
   main.bundle.js    2.51 MB    0, 2  [emitted]  main
 styles.bundle.js    10.2 kB    1, 2  [emitted]  styles
        inline.js    5.53 kB       2  [emitted]  inline
         main.map     3.1 MB    0, 2  [emitted]  main
       styles.map    14.1 kB    1, 2  [emitted]  styles
       inline.map    5.59 kB       2  [emitted]  inline
       index.html  489 bytes          [emitted]  
assets/.npmignore    0 bytes          [emitted]  
chunk    {0} main.bundle.js, main.map (main) 2.46 MB {1} [initial] [rendered]
chunk    {1} styles.bundle.js, styles.map (styles) 9.96 kB {2} [initial] [rendered]
chunk    {2} inline.js, inline.map (inline) 0 bytes [entry] [rendered]

WARNING in ./src/app/app.component.ts
18:55 export 'TestInterface' was not found in './test.service'

WARNING in ./src/app/app.component.ts
18:88 export 'TestInterface' was not found in './test.service'
Child html-webpack-plugin for "index.html":
         Asset     Size  Chunks       Chunk Names
    index.html  2.82 kB       0       
    chunk    {0} index.html 357 bytes [entry] [rendered]

5. Mention any other details that might be useful.

I could not reproduce the issue without adding the @Input() to the class member.

Compiling with tsc does not produce any warnings.

bufix faq

Most helpful comment

Same issue with @Input property decorator. Found workaround:

@Input() myProp = <MyInterface1>null

instead of

@Input() myProp: MyInterface1

now no warnings

All 140 comments

I get same issue when following the the dependency injection token example given in the angular docs - https://angular.io/docs/ts/latest/guide/dependency-injection.html#dependency-injection-tokens

Haven't checked if perhaps the docs have been updated but implemented in my app based on documentation as of maybe 2 months ago I get the following warning:
export 'AppConfig' was not found in '../app.config'
Whenever I import the interface.

Works fine despite warning so I've just been waiting for it to go away eventually as things mature

@TheLarkInn can you weight in?

Seeing the very same error as well.

This is a bug we identified but I need to find it in our webpack repo to link to this one.

having the same issue. (Works fine despite warning)
are you exporting more than one interface/class/const from the file?
issue stopped for me after i exported each interface from its own dedicated file.

meaning if i had one file with multiple exports - i got warnings in build (export 'MyInterface1' was not found in '../file')

file.ts

export interface MyInterface1 {}
export interface MyInterface2 {}

after refactor - no warning

file1.ts

export interface MyInterface1 {}

file2.ts

export interface MyInterface2 {}

Usually (and coming from the Java world), I'd consider it good style to split such multiple definitions into separate files anyway.
But given how Angular recommends injecting interfaces (with an OpaqueToken), it seems obvious to define the interface and its related token in the same file, triggering this error.

This issue is fixed for me after upgrading to angular-cli 1.0.0-beta.17 and angular 2.1.0

@teledemic interesting, I still have the same problem on those versions.

Huh! I recently upgraded all my packages. Not sure what it could have been other than those two. FWIW:

  "dependencies": {
    "@angular/common": "2.1.0",
    "@angular/compiler": "2.1.0",
    "@angular/core": "2.1.0",
    "@angular/forms": "2.1.0",
    "@angular/http": "2.1.0",
    "@angular/platform-browser": "2.1.0",
    "@angular/platform-browser-dynamic": "2.1.0",
    "@angular/router": "3.1.0",
    "angular2-highcharts": "^0.3.4",
    "bootstrap": "4.0.0-alpha.4",
    "core-js": "^2.4.1",
    "jwt-decode": "2.1.0",
    "ng2-bootstrap": "^1.1.14",
    "rxjs": "5.0.0-rc.1",
    "ts-helpers": "^1.1.1",
    "zone.js": "^0.6.25"
  },
  "devDependencies": {
    "@types/jasmine": "^2.5.35",
    "@types/jwt-decode": "1.4.28",
    "angular-cli": "^1.0.0-beta.17",
    "codelyzer": "~1.0.0-beta.1",
    "jasmine-core": "2.5.2",
    "jasmine-spec-reporter": "2.7.0",
    "karma": "1.3.0",
    "karma-chrome-launcher": "^2.0.0",
    "karma-cli": "^1.0.1",
    "karma-jasmine": "^1.0.2",
    "karma-remap-istanbul": "^0.2.1",
    "protractor": "4.0.9",
    "ts-node": "1.4.3",
    "tslint": "3.15.1",
    "typescript": "^2.0.3"
  }

I'm on Angular 2.1.0 and CLI beta 17. I have a structure looking like this:

import { OpaqueToken } from '@angular/core';

export const APP_CONFIG = new OpaqueToken('app.config');

export interface AppConfig {
  geoserverUrl: string;
  ...
}

which triggers a Warning:
export 'AppConfig' was not found in '../../app.config'
whenever I try to inject the named token, e.g.

constructor(private http: Http, @Inject(APP_CONFIG) private appConfig: AppConfig) {
  ...
}

If I make the AppConfig a class, it works without warnings. (Though of course it then has to be instantiated differently).
I makes me wonder if something in the build sequence just throws away the interfaces (too early), since they don't actually exist in the final JavaScript.

Same issue with @Input property decorator. Found workaround:

@Input() myProp = <MyInterface1>null

instead of

@Input() myProp: MyInterface1

now no warnings

Can anybody update on the status of this?. I'm at v1.0.0-beta.21, and still getting the warnings.

I get an error in CLI: Cannot find name 'HERO_DI_CONFIG'. (followed complete example on angular documentation). Despite the error, all is working fine an chrome console doesn't log any errors.

Just to add what knowledge I can, if you are using the APP_CONFIG example and getting the harmony warning, I moved the interface declaration (and just the interface declartion) into another file (iapp.config.ts),

export interface IAppConfig {
  API_URL: string;
}

imported IAppConfig into app.config.ts (since it is now in another file), and did the imports in the components separately, e.g:

import { APP_CONFIG } from '../app.config';
import { IAppConfig } from '../iapp-config';

Everything else remained the same (didn't have to convert it to a class etc). The extra file/imports are bulky, but no warnings and works as expected.

Recently trying to create a service provider (yup, also following the DI guide at https://angular.io/docs/ts/latest/guide/dependency-injection.html#!#injector-providers) and I copied the code into the hero.service.provider.ts file. It seems that it demands the file to export CamelCase instead of camelCase.

Took @Maistho repo for a spin.

After ng init, overwriting most files except for app.component.*.ts.
ng build still gives the warning:

Hash: cad6eef25bd1670f6646
Time: 10163ms
chunk    {0} main.bundle.js, main.bundle.map (main) 5.23 kB {2} [initial] [rendered]
chunk    {1} styles.bundle.css, styles.bundle.map, styles.bundle.map (styles) 1.77 kB {3} [initial] [rendered]
chunk    {2} vendor.bundle.js, vendor.bundle.map (vendor) 2.61 MB [initial] [rendered]
chunk    {3} inline.bundle.js, inline.bundle.map (inline) 0 bytes [entry] [rendered]

WARNING in ./src/app/app.component.ts
18:55-68 "export 'TestInterface' was not found in './test.service'

WARNING in ./src/app/app.component.ts
18:88-101 "export 'TestInterface' was not found in './test.service'

ng version is

                         _                           _  _

__ _ _ __ __ _ _ _ | | __ _ _ __ ___ | |(_)
/ _|| '_ \ / _ || | | || | / _` || '__|_____ / __|| || |
| (_| || | | || (_| || |_| || || (_| || | |_____|| (__ | || |
__,_||_| |_| __, | __,_||_| __,_||_| ___||_||_|
|___/
angular-cli: 1.0.0-beta.26
node: 7.4.0
os: darwin x64
@angular/common: 2.4.4
@angular/compiler: 2.4.4
@angular/core: 2.4.4
@angular/forms: 2.4.4
@angular/http: 2.4.4
@angular/platform-browser: 2.4.4
@angular/platform-browser-dynamic: 2.4.4
@angular/router: 3.4.4
@angular/compiler-cli: 2.4.4

I still have this warning, as @catull reported.

The current workaround that @Iverson suggested works for me.
But I didn't understand what it meant at first.
It's a typescript type cast, it says "in myProp there is a null value (initially), but it WILL be of type MyInterface1

It can also be written as:
@Input() myProp = null as MyInterface1;

I'd really like to see this resolved

I am still experiencing exactly the issue described by @wulfsberg.

import { OpaqueToken } from '@angular/core';

export let SKYPE_CONFIG_TOKEN = new OpaqueToken('skype.config');

export interface SkypeConfig {
    ...
}

Everything works, but I get this warning:

105:93-104 "export 'SkypeConfig' was not found in './skype.config'

As this seems to be legal (and recommended) code, it would be better if it did not throw a warning.

There is simpler & better solution: move all interfaces in a relevant `myfunctionality.interfaces.ts' with a normal exports

export interface MyFunctionality {
   foo: string;
}

and it works like a charm, with no warnings. And it separates your interfaces into their own files, which is nice.

This issue is very annoying.
Could you please fix it?

Also waiting this issue to be fixed since a long time..

If you extend an interface the warning remains when you split the interfaces in files
image

This is getting more attention from users than it should, and less attention from maintainers as I see the dates. Anyway, I come here not to complain (since I know the problem is hard), but to provide a valid workaround.

Our team uses a lot of interfaces. But also a lot of barrels (those index files where you simply re-export public stuff). A workaround that is working perfectly for us is using explicit re-exports, i.e:

Instead of using export * from './file-with-interfaces'; in that index.ts, we do export { SomeClass, SomeType, AnInterface1, AnInterface2 } from './file-with-interfaces';

Later using import { SomeClass, AnInterface1, OtherClass } from './the-folder-with-barrel'; works in the app and shows no warnings. I expect this may help some sorrowful souls ;).

PS: we have 62 interfaces and 0 warnings with this method ;)

I made the same suggestion as @ShadowManu just above and got 3 negative votes - it 'd be nice if you explained your reasons :+1:

@anodynos Fragmenting your code into double the number of files to use an Angular-ideomatic OpaqueToken is sub-optimal. As I mentioned, I come from the Java world and am fairly used to the "one file, one interface" style, but in this case it really feels like the wrong thing to do. (And from a language perspective, it should just work).

Vanilla ES6/ES7 rules!!!

* ducks *

@anodynos there's a couple of differences though. 1) you're not forced to put interfaces aside. Just put them where you deem necessary. 2) The barrel with explicit re-exports is somehow (yeah, I don't get the particular reason) the one making the warnings go away.

@anodynos @ShadowManu
The solutions you suggest don't solve the problem, they are just workarounds:

  • @anodynos I do want to keep the OpaqueToken and interface in the same file;
  • @ShadowManu I do not want to be forced to use barrels.
    As it was stated by @wulfsberg , it should just work from a language perspective and I think this is the main reason why you are getting thumbs down. Personally, I prefer getting the warning messages than adopting any of those two workarounds.

Thanks @JulienBroi - some some comments:

  • You dont need the OpaqueToken & IOpaqueToken or whatever in the same file - you can have an opaque-token-interfaces.ts or opaque-token-types.ts and stick all the interface & type related stuff in there.

  • What wrong with barrels?

I don't need it, but I want it, the language allows it, and Angular recommends it. Insisting that I have to do it in another way because of a bug is not a good solution.

It is a workaround and shouldn't be needed. But for those desperate, there's something that can be done in the meantime. Reverting is later as simple as deleting the files and following the broken imports.

Could a maintainer lock this issue? I'm getting my inbox spammed and none of these comments are helpful.

@MazeChaZer All you need to do is to click on the "Unsubscribe" button above on the side.

@catull I would like to get notified when this issue is resolved

For the record, the corresponding issue in webpack is webpack/webpack#2977.

As @hccampos explains there, it touches classes with decorators (annotations):

classes that contain decorators and are using an interface imported from another file trigger the warning. While everything works normally, it would be nice to get rid of the warnings.

Personally I can say it is actually only for the class of a class member annotated with @Input that I see the problem, it is not because of the class itself:

@Input() component: IComponentRow;

will trigger:

WARNING in ./src/app/features/cockpit/workspaces/petals-content/petals-component-view/petals-component-overview/petals-component-overview.component.ts
46:50-63 "export 'IComponentRow' was not found in '../../../state/components/component.interface'

The problem is not because of webpack but most certainly because of something typescript/decorators related (as explained by @sokra: https://github.com/webpack/webpack/issues/2977#issuecomment-245887841). The interface is referenced in the javascript code generated by typescript and thus webpack can't find it (since they have no real existence in the javascript realm).

@filipesilva so I think the problem is coming from typescript itself.

I have a similar situation. I have multiple interfaces in the same file, all exported. From other files I import those and get a warning that it cannot find them. If I split each interface to its own file, the warning goes away.

Sometimes I have interfaces and classes in the same file, same result when importing the interfaces.

```WARNING in ./src/app/shared/services/ai.service.ts
368:57-64 "export 'IConfig' was not found in '../models/app-insights'


 ```// app-insights.ts
export interface IAppInsights {
  // ...
}

// some-other-file.ts import { IConfig } from '../models/app-insights'; // ...

Things that worked:

  1. split each interface to its own file
  2. make them abstract classes

VS Code is happy with this. VS Code can find the import, can navigate to the definition. So it seems to be OK using TypeScript ... but the compiler is not.

cc @alexeagle as an FYI

Ths appears to be a TypeScript thing. ?

we changed our tsconfig.js module from es6 to commonjs and warnings were gone, based on generated code I'm not sure whats different.

Input decorator code with es6:
__decorate([
__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__angular_core__["Input"])(),
__metadata('design:type', (typeof (_a = typeof __WEBPACK_IMPORTED_MODULE_1__models_user_info__["UserInfo"] !== 'undefined' && __WEBPACK_IMPORTED_MODULE_1__models_user_info__["UserInfo"]) === 'function' && _a) || Object)
], HeaderComponent.prototype, "user", void 0);

Input decorator code with commonjs:
__decorate([
core_1.Input(),
__metadata('design:type', (typeof (_a = typeof user_info_1.UserInfo !== 'undefined' && user_info_1.UserInfo) === 'function' && _a) || Object)
], HeaderComponent.prototype, "user", void 0);

We need a better way to isolate which layer is causing the problem - it seems like angular CLI magic is making this difficult. Perhaps a minimal repro without the CLI would help?

@alexeagle I dont have a minimal repro, though I will try to find a better one.

In the meantime, if you clone this repo and branch, run npm i, then run ng b you will see the issues I mentioned.

https://github.com/projectkudu/AzureFunctionsPortal/tree/upgrade-angular-v4

Sorry, I won't have time to dig in today. The warning does come from webpack, right? Could it be that TypeScript has erased the interface from the output .js file, but some other code still references it? (try pasting the .ts content in the TypeScript playground to see what it emits)

No worries, no rush. It's a warning, not an error.

The typescript compiler outputs an empty file. But there are other interfaces in that file which are fine.

Another interesting observation is that if I move each interface to its own file, the warning goes away

I am also experiencing the same thing, but it happens with type aliases export type MyTypeAlias = .... as well, not just interfaces.

I used to just be able to ignore this warning, but now after upgrading to @angular/cli 1.0.1 it will give an error in the browser saying "Failed to compile" along with the error about my interface not being found in the source file. Why is a warning stopping it from running?

In @angular/cli: 1.0.1 I have not warning, but error:
2017-04-26

Should I put every single interface or type in a separate file? Even very small? For example:

export type SelectorDataMapperFn<T> = (term?: string) => Observable<T[]>;
export type SelectorListItemMapperFn<T> = (value: T) => SelectorSelectItem<T>;
export type SelectorCompareWithFn<T> = (value1: T, value2: T) => boolean;
export type SelectorCreateNewItemFn<T> = (value: string) => void;

In separate file each? Is it all right?

@manofearth At the moment it is the only possibility to get around the error.

Yeah, updating from 1.0.0 to 1.0.1 prevents the UI from loading at all now. The errors displayed (like in @manofearth 's picture) are still displayed in the console logs as "WARNING"s though - not errors. 1.0.0 doesn't block the UI though.

I found that error disappears if I switch imports from import { X } from './x' to import * as ModuleX from './x'. But it's not very convinient to prepend all X usages in code with module alias: ModuleX.X.

Hi,
`
// test.ts
export interface test {}

// app.ts
import { test } from './test'
`
I don't get any warning but the import resulting undefined

same issue

If you put all the interfaces alone in a single type (say a types.ts file) and then import them from there, you should get no errors.

The problem happens when there is some non-type-related code in a file mixed with some types and interfaces. In that case, webpack tries to import a file and look for a symbol in it but it doesn't exist. If the interfaces are all in a separate file, they are only used by TS for type checking and webpack doesn't care about it.

Hmm, I did separate it; yes no error, but by the time i import the file, i
could not reference the interface which i exported.. It's declared as
undefined thus produce errors at later codes; am I missing something?
On Thu, Apr 27, 2017 at 6:39 PM Hugo Campos notifications@github.com
wrote:

If you put all the interfaces alone in a single type (say a types.ts file)
and then import them from there, you should get no errors.

The problem happens when there is some non-type-related code in a file
mixed with some types and interfaces. In that case, webpack tries to import
a file and look for a symbol in it but it doesn't exist. If the interfaces
are all in a separate file, they are only used by TS for type checking and
webpack doesn't care about it.


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/angular/angular-cli/issues/2034#issuecomment-297689689,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ACmP2QobYmOgxcKUOLSh9fbt6xgsdfljks5r0H5mgaJpZM4J5QId
.

thanks but can't we fix it, i know it works with workaround but can't move all my interfaces in each module to one file. need fix

@hccampos

@istiti to be honest, I don't see this getting fixed soon. It is not really an Angular CLI problem, and it is not really a Webpack problem. It is not a Typescript problem either... it is sort of in-between everything, and no one party can easily fix it, I think.

I'm curious if the CLI is using Rollup. I've experienced the same kind of issue on an Ionic 2+ project when I used Rollup instead of Webpack to bundle. So if the CLI uses Rollup, I think it might be where the source of this issue resides.

Just FYI for everyone here, the warnings don't block the UI on 1.0.2 or 1.1.0-beta.0, so you can upgrade past 1.0.1 if you need to.

Hi everyone, I'm having the same issue. I was following angular's styleguide by using classes instead of interfaces for type definitions, but decided to refactor and use interfaces instead and discovered the warning message.

However, now that I see that this hasn't been solved yet, I changed back to classes.

My question is, why use interfaces instead of classes? What's the real difference?

Why? A class can act as an interface (use implements instead of extends).

The difference between a class and an interface is this. The class says something about how the thing is constructed. What kind of code it has running behind it. Which may contain methods and so on. The interface only talks about the shape of data. So in terms of communicating to fellow developers the meaning of the code, and interface is the most clear way to talk about data your application does not construct and knows nothing about the construction of. For example, some data arriving over the wire as JSON then deserialized - it won't ever really be an instance of any class other than Object. But it may structurally match an interface.

TypeScript has an interesting "hack" around classes. If you define the class which only has fields, you can then treat it much as an interface. It will even pretend that an object is an instance of a class of which it is clearly not, the class only has fields (and therefore works like an interface). I think that is a horrible idea, I don't think it is a good feature, and should be removed. But no one asked me :-)

The difference becomes stark as soon as there is a method added. Once a class or interface has even a single method, the ability to pretend they are the same evaporates.

Agreed @kylecordes, this statement is probably misusing context: "I was following angular's styleguide by using classes instead of interfaces for type definitions".

A class and an interface serve two very different purposes. One is about concrete implementation, the other abstracted behavior. I'm confident the Angular style guide would not equate the two as interchangeable.

@Snesi , the difference is, a class is a concrete thing. For example, "Car" is not a behavior, or (as Scala calls them, which to me makes a lot more sense than "interface"), a "trait". Car IS Car. But, "Car" can be "Drivable". That's a trait that can be shared across different kinds of things; a Bike, a power mower, etc. If you were to say, "Oh I just create ICar, IBike, IPowerMower"...that's misuse, which always leads to your question, "why bother with interfaces?" Better to do something like "Vehicle" (subclass Car, Bike, PowerMower), with traits IDriveable, IFuelable, etc. This way, you can even have a vehicle, say, that isn't drivable, you would create "IRemotelyOperated" or some such. ISelfDriveable extends IDriveable. You get the idea. Now you can have a Car that can be operated a variety of ways, specified by different interfaces.

But if you just create an interface that does nothing every time but mirror the entire implementation of a specific concrete thing, you'll find you end up with a lot more interfaces than you should, because there's no behavioral abstraction, and interface will just appear superfluous.

@tcoz @kylecordes Thank you, I understand the difference in languages like Java or PHP, but if Typescript allows to use a class like if it's an interface, why not embrace that hack?

Also, you are right @tcoz. I misinterpreted the angular guideline. This is what it says about interfaces:

Do name an interface using upper camel case.

Consider naming an interface without an I prefix.

Consider using a class instead of an interface.

Why? TypeScript guidelines discourage the I prefix.

Why? A class alone is less code than a class-plus-interface.

Why? A class can act as an interface (use implements instead of extends).

Why? An interface-class can be a provider lookup token in Angular dependency injection.

It just says to consider using a class instead of an interface because it can be implemented instead of extended and because it can be a provider lookup token for dependency injection in Angular (I have no idea what that is)

I would say for the very reason you suggest: it's a hack. I'm not sure language is a determining factor. An interface is an interface.

Now, if TypeScript has underlying technical reasons for not using interfaces the way everything else does because the language itself can't support it properly, that's a different matter. But they should make it clear that this is the case. And increasingly, it does seem interfaces can be problematic in TS.

Also the whole "without the I" thing is dubious. The C# style guide, very first example of Interface, shows:

interface IEquatable

(Note also the name implies a behavior, not a concrete "thing").

So it seems contradictory to me that TS would say "no" but C# clearly says "yes", unless the point was to be able to tell a C# interface from a TS one...which again, would be a questionable practice IMHO. Or, again, unless the reason was the underlying technology itself.

Also, say you're iterating a collection and filtering on some types. Are they interfaces, or class types? How do you know just by looking at the code? In a review (like a GitHub side-by-side), where's there's no hover tooling and so on, that could be very annoying.

Why depart from such a useful standard? Myself, that's one TS thing (if it is in fact a formal recommendation) I might discard.

I've had a read of the styleguide, and I think it's simply poorly worded. What I believe it means is instead of doing this:

interface IItemService {}
class ItemService implements IItemService {}
class OtherService {
  constructor(itemService: IItemService) {}
}

to do this:

class ItemService {}
class OtherService {
  constructor(itemService: ItemService) {}
}

This is because in the latter case, the class itself can be injected by-reference (this is what the "provider lookup token" bit means - the class constructor is used as the thing to identify what we're trying to inject here.)
The style guide is simply advising against a pattern that is quite common e.g. in Java with Spring, where every dependency should be an interface and then the DI framework figures out which implementation to use. It states that in Typescript that creates unnecessary overhead, and in 99% of cases your interface would only have one implementation anyway so it's unnecessary to prematurely optimise this by leveraging polymorphism.

I don't believe the style guide is actually stating "use classes instead of interfaces always" - I think it's stating "use just classes instead of class-plus-interface for injectable classes."

Regardless, I believe this is quite off-topic and is just making a long thread longer, so we should probably stop discussing the style guide.

@tcoz

Also the whole "without the I" thing is dubious. The C# style guide, very first example of Interface, shows:

interface IEquatable

(Note also the name implies a behavior, not a concrete "thing").

If you go by that logic, You don't need to pretend I to Equatable to know that its a behaviour. The able sufix of Equatable clearly implies this is a interface.

So I is completely redundant in this example.

Some pretty easy examples where that doesn't work. Example: "IComponent", "IProvider". That would have to be "Compentable", "Providerable". That'd just be odd. Those btw are again from C#.

I really can't see a valid reason to make TS different from everything else on earth that way, particularly it's closest analog, C#.

I'm sorry to have brought this up, but continuing this discussion about code style is completely off-topic xD.

For now, just so I don't see the warning export 'TestInterface' was not found in './test.service' I preferred to use classes instead of Interfaces, because I don't want to split every Interface into separate files.

And thanks to typescript's "hack" that allows you to use classes like if they were interfaces, whenever this bug is fixed, I could change the classes to interfaces and everything should continue working without issues.

Just to obscure this weird error a bit more... I have the same warning for:

// Warning: "export 'BillState' was not found in '../../state/reducers/bills'
@Input() bill: BillModel;

However, if I change the type to be an array of BillModel the error is gone.... :sheep:

// No warning :-)
@Input() bill: BillModel[];

@gionkunz I have the same behavior as you, except that it's crashing my entire site. It's only in certain files, when I import the interface and assign it as a type, I get the error datatypes_1 is not defined. datatypes is the folder that my interface sits in. It does not matter if I import the interface from the index file in datatypes or straight from the file where it is exported. But, if I cast the object as an array, I can build the project.

I'm experiencing the same issue when referencing interfaces from third-party modules.

Heya all, I've been looking at this problem and wanted to give you an update.

There's two parts to the issue:

  • interfaces don't really exist after TS compilation.
  • Webpack tries to follow imports on ES modules.

So for things that need to exist and be imported after compilation, like a decorated type (e.g. @Input() test: TestInterface), you will get a warning that the import cannot be found by webpack. It simply does not exist anymore after compilation (AOT does not suffer from this problem btw).

A couple of workarounds have been proposed, like keeping files that only have interfaces, or declaring the interface in the same class that uses it. These address the problem in different ways.

When you have a file composed only of interfaces, it is empty after compilation. So Webpack thinks it's a CommonJS module (instead of a ES module) and doesn't try to figure out it's exports, assuming whatever we're importing is there at runtime. See https://github.com/webpack/webpack/issues/2977#issuecomment-245898520 for more details.

Declaring the interface in the same module where you use it means there's no export to follow, so no warning.

I checked with the TypeScript folks (@mhegazy, @DanielRosenwasser) and @alexeagle, and this is indeed an unfortunate situation for which there is no clear fix.

The recommendation is to use a value that exists after compilation for decorated properties. For instance, a class or variable instead of an interface.

I know this is frustrating because you are encouraged to fully make use of TypeScript, but it is a current limitation.

I'll communicate this to docs to make sure guidance is provided.

Thanks to all that have been following this, providing context, reproductions and workarounds. I'm sorry I don't have a real fix that just makes it go away.

+1

@filipesilva So the best practice is to use class instead?

@wilsoncook yes.

I just got this warning for the first time today, apparently because I had a file that exported a const as well as an interface. The weird thing is I had already been using the interface elsewhere (within Providers and within other models) for a while without problems. The warning didn't crop up until I tried to use the interface from a component.

The workaround was to move the exported constant out of that file. It seems as long as individual TS files contain only compile-time constructs (e.g. types, interfaces) OR runtime constructs (classes, consts), but not mixed, then the warning will not occur.

IMHO, this seems like a much better approach than telling people to switch to using classes everywhere, because while TypeScript might treat class type annotations the same way as interface type annotations, the semantics of classes in JavaScript itself are quite different. Classes in JavaScript > ES2015 mean you're expecting certain methods and you're expecting a certain prototype and a certain constructor with possibly certain static fields on it, and you're expecting to be able to "instanceof" it and always get true if it matches. To abuse classes to get type-safety on plain JS data objects is not the right way to go, IMHO.

@mischkl same concern

So the best practice is to use class instead?

@filipesilva But as I understand it adds extra unused source code to the resulting bundle or I miss something?

IMHO, this seems like a much better approach than telling people to switching to using classes everywhere

@mischkl The thing is you can't completely split interfaces and the real code in some situations.
Here is one of them:

import {SomeComponent} from './some.component';

export interface SomeInterface {
  ref: ComponentRef<SomeComponent>;
}

In this case you have to import the real component to describe an interface and resulting file won't be empty after compilation.

@th0r the example you mention should not be a problem. The problem only comes when you export a mixture of compile-time and run-time stuff in one file, e.g.:

export class SomeClass {
  foo: string;
}

export interface SomeInterface {
  bar: string;
}

@mischkl I mean your solution (extracting all compile-time stuff into a separate file) won't work for my example: I extracted SomeInterface but it depends on run-time code (SomeComponent) and resulting file won't be empty after compilation.

@th0r I guess I didn't specify what I meant exactly enough. You can mix and match compile-time stuff with non-compile-time stuff as much as you want AFAIK, the only problems come when you export both from one file.

So the solution is to separate out all interface and type exports into extra files, which can then be imported elsewhere and used freely.

So the solution is to separate out all interface and type exports into extra files, which can then be imported elsewhere and used freely.

This won't work for my example because of this (quote from this comment):

When you have a file composed only of interfaces, it is empty after compilation. So Webpack thinks it's a CommonJS module (instead of a ES module) and doesn't try to figure out it's exports, assuming whatever we're importing is there at runtime.

In my example this file with interfaces won't be empty because you imported SomeComponent into it that is needed to describe SomeInterface.

@th0r why don't you try it out? I think you'll find that the result is empty, despite your expectations. Keep in mind you are using the class here as a type annotation only, and more importantly you are not explicitly re-exporting it. From the outside all that is exported is the interface which consists of type annotations and nothing more.

@mischkl I'm sorry! You're right - just tried to extract them into separate files again and warnings have disappeared. Seems like I did something wrong first time 🤔

@filipesilva is there a typescript issue for this that can be referenced by this issue for future tracking if it gets fixed?

@zakhenry not that I know of, no.

Is there a reason why these warnings fail execution in the browser when its just warnings and not errors? As mentioned by someone in [email protected] it seemed no showstopper for development but as of [email protected] it halts development completely when it happens. My team is in the progress of migrating an app with 150+ components and suddenly this issue appeared for us. I'm still goofing around trying to find workarounds. It seems to have appeared completely random after having migrated roughly 30 components.. EDIT: Upgrading first helps.. had a specific version entered in package.json facepalm

So far I've found that any kind of union type on affected decorated properties will remove the warning, e.g.

@Input() someProp:MyMagicalInterface

will result in a warning while

@Input() someProp:MyMagicalInterface | undefined

will work. And to get completely funky

@Input() someProp:MyMagicalInterface | MyMagicalInterface

does work also. ¯_(ツ)_/¯

for whatever it's worth ... when you change the module in the tsconfig to "commonjs" the error goes away. This may not work for most situations, in mine it does because I am using a core module that is compiled outside of the cli project (with ngc) and later linked into it.

// ./src/app/wx.d.ts
export declare function config(): void;
// ./src/app/app.component.ts
import * as wx from './wx.d';

// using
wx.config();

ng serve throw Module build failed: Error: Debug Failure. False expression: Output generation failed.

Changing tsconfig module to "commonjs" fixed the warnings for me. Previously it was set to "es2015"

is there a way to just silence that warning?

@remmeier see the comment a few above - you can suppress the warning simply by making the type a union of itself. The same type safety is achieved, and the warning goes away. It is by no means a fix, but at least you can continue developing

The issue still exists, why is this closed?

@RenaldasK there is long explanation (shortly - it is the limitation which currently cannot be solved) https://github.com/angular/angular-cli/issues/2034#issuecomment-302666897

Try to rewrite interfaces to classes if possible (this works for me).
Or one of the proposed solutions above (i did not try any of them).

Aside from the console warnings, is there any actual reason to avoid this issue?

All of the solutions above feel like a hacks, and putting a single line interface in its own file seems like a waste of time...

Having the same issue with a scenario like this:

export class Something { ... }
export type SomethingKey = Pick<Something , 'keyPropertyName'>;

in one file. However when I add another interface, class or type to that file, the interface is resolved perfectly fine. This seem to be only the issue with the Pick<..> type. It works, compiles, transpiles, it only gives a warning in the CLI...

@filipesilva
Thanks for looking into the problem in detail. Easiest workaround I have found is to declare a local alias type in the component file for the imported type when needed in an @Input().
So for your example, rather than:

import {TestInterface} from ...
...
@Input() test: TestInterface

do a

import {TestInterface} from ...
type TestInterfaceAliasHack = TestInterface;
...
@Input() test: TestInterfaceAliasHack

This is really annoying. Is there a real fix and not simply temporary workarounds?

This issue's very Annoying !

For the time being just a flag to silence the warnings would be great as everything works perfectly fine regardless of the warnings.

They said working on it, i have the same issue just have to wait or work with a work-around if possible.

Guys this issue was explained here: https://github.com/angular/angular-cli/issues/2034#issuecomment-302666897

This is a problem with about how Webpack works. @filipesilva is there any chance this will be fixed some day? Are there open issues to address this problem?

Frustrating, but just use a class instead of an interface and it will work without any warnings.

I was facing the same issue on and @Input() types by an interface.
Solved by having one file with only interfaces (and type definitions), and moving constants and classes to a different file. A little bit of a headache but not as bad as requiring separate files for every interface or type or anything like that.

Still, if what someone above said is correct and cli is happy with:

@Input() foo = null;

I do not see why the trans-compiled code should be much different for:

@Input() foo: Bar;

To the extend that webpack will implode. Is there some specific semantic difference between the two (besides the explicit null assignment)?

I noticed that this error occurs when I try to export an Enum and an Interface in the same file. Since I split the Enum declaration of the Interfaces declarations, it's fine, even if I define a lot of interfaces in the same file. I didn't like to split my interface and enums into differents files because they share the same "domain context" in this case, but it's was the only way to get rid of this warning.

In Angular 4.3.1,
I strangely get similar errors when importing into one .ts file but not another one in same folder.
Again, the same import works fine in one file, but the other one gets

WARNING in ./src/app/foo/bar.ts
19:50-54 "export 'Tags' was not found in '../tar/tag.model'

with tag.model.ts being

export type Tag = string;
export type Tags = Tag[];
export class TagSet {
    constructor(public category:string, public tags:Tags[]){}
}
export type TagList = TagSet[];

@polyglotinc, I would think the reason you only see the problem in one file is because of the way the imported types are used. In my case a file containing something like:

@Input() foo: Tag; // This will cause the warning
@Input() bar: Tag[]; // This will not cause the warning

The reason I think is that after transpilation you still need to know what "Tag" represents on the former, but not for the latter, which is just a JS Array.

I got around this setting it equal to null and casting the type:

@Input() foo = <SomeType>null

This will fix it:
@Inject(MD_DIALOG_DATA) public order: Order | undefined

Might be better for null-checking. There is more info on the webpack issue: https://github.com/webpack/webpack/issues/2977

Also using a class instead of an interface might fix it

Additionally, you can use @Input() property: PropertyType | null; to get around this. Not sold on this workaround, or any other workarounds though. They're just bandaids slapped on the underlying problem.

Hello,
I having warnings when I export a string literal type from one file and import it in another.
I've managed to get rid of the warnings by moving that string literal types to a d.ts file.
Hope it helps !

Heya all,

I've been working on a new compilation pipeline for Angular 5 and up that should take care of these warnings in addition to other type related issues.

My warning in the console:

Warning: ./src/app/scheduler/event-form/event-form.component.ts
111:78-86 "export 'DayEvent' was not found in 'app/scheduler/month-view/month-view.component'

I fixed the warning by doing:
@Input() event: DayEvent | null;

instead of doing:
@Input() event: DayEvent;

I had the same problem, but couldn't use the type union because my input was a setter:

@Input() set something(s: SpecialInterface) { /** */ }

The switch from es2015, as set by the @angular/cli application generator to commonjs as noted above solved it for me.

@Inject(APP_CONFIG) config: AppConfig | AppConfig

is really strange workaround, but it just works xD

yep, I can confirm what @vpArth states worked for me also.

I am getting this warning for interfaces imported via a feature module library, however the strange workaround works to suppress the warning.

import { AccountSummary } from '@mylib/core
export class OrderComponent implements OnInit { @Input() account: AccountSummary; ...

I had the same problem exporting an interface:

export interface ResourceRef {
  [id: string]: {
    expires: string;
    resources: Array<Ref>
  };
}

and using it with @Input() resourceRef: ResourceRef;

Then I simply changed the interface to be a class, which johnpapa also suggested here:

export abstract class ResourceRef {
  [id: string]: {
    expires: string;
    resources: Array<Ref>
  };
}

And the warning is gone.
Now, is there any downside to that?

@rafaelbiten using a class, even abstract, will generate extra code for that class when compiled. An interface gives type checking for plain objects without generating additional code.

Has this been resolved? I am not seeing the errors with the following versions and import (although originally I was using abstract class

Angular CLI - v1.6.0
TypeScript Workspace Version: 2.4.2
TypeScript VSCode Version: 2.6.1

import { InjectionToken } from '@angular/core';

export interface ContentfulKeysConfig {
  space: string;
  accessToken: string;
  contentTypeIds: {
    post: string;
  };
}

export const CONTENTFUL_KEYS_CONFIG = new InjectionToken<ContentfulKeysConfig>('contentful-keys.config');
import { CONTENTFUL_KEYS_CONFIG, ContentfulKeysConfig } from './config/contentful-keys.config';
private keysConfig: ContentfulKeysConfig;
constructor(@Inject(CONTENTFUL_KEYS_CONFIG) config: ContentfulKeysConfig) {
    super();
    this.keysConfig = config;

Why is it closed?

Still seeing the issue for Angular CLI v1.6.3. Why is it closed?

This issue is happening. I have a one big ts file with many interfaces defined. Only two of those interfaces are causing this warning during build. However I'm able to import the interfaces just fine and intellisense is working for the affected interfaces. The stack trace shows the warning is triggered by the cli package. I assume this is ok to ignore as long as it build properly?

I assume this is ok to ignore as long as it build properly?

yes @yangwen2

In case anyone's looking for it, this appears to be the upstream webpack issue that @TheLarkInn mentioned!

https://github.com/webpack/webpack/issues/7378

In my case, restarting ng serve helped. I had only one export in my ts file

I just restarted the server and the warnings are gone.

This is not an issue anymore. I used abstract class instead.

This is not an issue anymore. I used abstract class instead.

is there any impact on types if we change interface to abstract class

Got this issue today when updating angular's packages to 8.0.4 / 0.800.4

https://github.com/angular/angular-cli/issues/2034#issuecomment-249813801 fixed it for me

Having this issue after upgrading to angular 8

Having this issue after upgrading to angular 8

Just move out app the interface/types from the problematic file into a separate *.ts file and don't add the actual code there.

@th0r do you mean the interface thats causing the issue to remove them and put them into there own separate file

@hijazikaram yes. In my projects in case of such errors I just move all the interfaces/types from the file that triggers an error into a separate file e.g. <filename>.types.ts and export all of them. Also this file should not contain any real code e.g. classes, functions, variable etc.

Same issue. Moving interface to a separate file doesn't help if use barrel.

Same issue. really don't want to move interfaces to separate files. Also, issue for aggregator ts files that do a lot of export * from.

@jeffwhelpley I just added | null which fixed the issue for me

Why is angular/typescript making it hard for us? 😞

same as @mpgo13. I started getting the issue when updated to version 8.0.4 / 0.800.4,

But in my case #2034 (comment) didn't work for me.

Error is not just happening within my own libs, but also in one of the ngrx libraries

@tbnovaes I got the same issue few days ago. After setting the fixed version of angular devDependencies to 8.0.0 / 0.800.0 it was gone.

For those of you who got this error after upgrading to 8.0.4 / 0.800.4, see https://github.com/angular/angular-cli/issues/14876. A fix seems to be coming in the next release.

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

_This action has been performed automatically by a bot._

Was this page helpful?
0 / 5 - 0 ratings