You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Should be possible to force import of "unused" modules in case there are side-effects #9191
// A self-contained demonstration of the problem follows...import{ngModule}from'./../module.ts';exportclassMyService{}ngModule.service('myService',MyService);// <- REALLY IMPORTANT SIDE-EFFECT
Reacted by Balazs Erdos, Richard Liu, Matthew Layton, Arthur Masson, Hamid Mayeli, Rafael Cepeda, Michał Wadas, ali-hamud, Kostia P, Keith Armstrong and 16 more
Reacted by Nicola Pacucci, Artur Madjidov, Caio Augusto Araújo Oliveira and victorgsp
Aleksey-Bykov Basically, in Angular code, the class is instantiated by the dependency injection system, so you import MyService but then you don't new it or anything, you just use it as the type for the injected parameter. TypeScript sees that you don't actually use the class except as a type declaration, which has no meaning in the emitted JavaScript, so it sees no reason to include it in the emitted JavaScript. It makes perfect sense, except when the file you are importing from has side-effects; in this case, the registering of the service with an AngularJS module.
Reacted by Michael Zalla, Adam Palaniuk and David Lung
While I get understand the use case, I can't conceive of a clean syntax that would denote that the import should not be elided... Only except maybe:
import*,{MyService}from'./MyService';
In that the compiler would understand that the anonymous * is denoting that the import is being doing for side-effects but not being named. Therefore:
import*from'./MyService';/* is equivalent to */import'./MyService';
The one "edge case" is that if the default export of the module being something that gets erased (is that even possible to export default something that is erasable)?
This ensures the service import will not be elided. It also has the advantage of decoupling your service classes from angular (sure $inject is there but they don't depend on angular).
Edit: Updated example with explicit export from "app.ts"
Aluan Haddad (@aluanhaddad) I see what you've done there, but I use ngAnnotate as part of my build process so I don't have to manually maintain $inject properties, and I don't think ngAnnotate would pick up that way of adding services... although I'll give it a try.
This would all go away if my boss would just let me spend 6-9 months rewriting the entire application in Angular 2...
@markrendle I don't use ngAnnotate so I wouldn't know if that would work but the only reason I write my "services" as classes registered with .service instead of factories registered with .factory is to take advantage of the static inject notation. That said, I only used the above style for my example because it is my preference.
My example was just meant to show that you don't have to register each service in the module where it is defined. I also think that there are compelling reasons to avoid doing so.
Regardless, using a tool like ngAnnotate shouldn't dictate the way in which you structure your code or the order in which you register your services.
Kayvan Arianpour (@karianpour), to the original issue in this thread yes, just do double import once of the type and once just of the module with no types, look at the start of the thread for details
I use export * from './MyService' where myservice.ts exports default like export default class MyService {}.
It doesn't reexport anything but it do force to execute the side-effect codes.
If you use barrel files(index.ts which re-exports module), every file must export an empty default value as below, to prevent tree-shaked by ts compiler.
index.ts
export * from './a';
export * from './b';
export * from './c';
export default {}; // <- this is required
PS: I prefer export * from './MyService' rather than import './MyService' because the former reports a error path while the latter doesn't.
In MainFilter.ts I use import { conf, IData } from './MainFilter.conf'; and in dev-mode for browser use <script type="module">
MainFilter.conf.ts has interface IData:
In browser console I have an error: Uncaught SyntaxError: The requested module './MainFilter.activity.conf.js' does not provide an export named 'IData'
cause of tsc cutting out interface export from MainFilter.conf.js =(
How to solve it? Why MainFilter.js not cutted out IData?
Unfortunately, I find this is a pretty common situation when working with custom elements, and as a library author I'm frustrated that I can't fix this for library users. It also makes it trickier to recommend TypeScript to beginners. The only way to allow elem2 to be commentable in the code above is to change the imports to the following, which I think should be considered an anti-pattern (I would flag it in a code review):
Given that TypeScript will probably treat import ClipboardCopyElement like import type ClipboardCopyElement in the foreseeable future, it would still be really useful to have "import with side effects" (ideally still compatible with normal JS syntax). This:
Lately my eye caught a compiler/tsconfig option called importsNotUsedAsValues when I was browsing the TSConfig Reference on the TypeScript website. Perhaps this issue here is solved when specifying the value preserve or error for that option?
Sorry if I'm confused about why this is closed. This hasn't been fixed, has it?
It would be nice to have something that is the opposite of import type that tells TypeScript we want to actually import the file, even if the things we're importing just so happen to be types.
Right now, we have to do this:
import type { MyType } from './file';
import './file';
Is there a way to shorten this? If not, maybe something
import value { MyType } from './file';
import type indicates we only care about these imports in type space, and import value tells TypeScript that there is something in file.ts that we need in value space.
Activity
RyanCavanaugh commentedon Jun 15, 2016
It's possible:
import './MyService`;ThatRendle commentedon Jun 15, 2016
I know I can do that, but I shouldn't have to say
all over the place. It's just untidy.
ThatRendle commentedon Jun 15, 2016
:)
zpdDG4gta8XKpMCd commentedon Jun 15, 2016
I am too dumb for getting why
import {MyService} from './MyService';would not work, please enlighten.mhegazy commentedon Jun 15, 2016
please see https://github.com/Microsoft/TypeScript/wiki/FAQ#why-are-imports-being-elided-in-my-emit
ThatRendle commentedon Jun 16, 2016
Aleksey-Bykov Basically, in Angular code, the class is instantiated by the dependency injection system, so you import
MyServicebut then you don'tnewit or anything, you just use it as the type for the injected parameter. TypeScript sees that you don't actually use the class except as a type declaration, which has no meaning in the emitted JavaScript, so it sees no reason to include it in the emitted JavaScript. It makes perfect sense, except when the file you are importing from has side-effects; in this case, the registering of the service with an AngularJS module.kitsonk commentedon Jun 16, 2016
While I get understand the use case, I can't conceive of a clean syntax that would denote that the import should not be elided... Only except maybe:
In that the compiler would understand that the anonymous
*is denoting that the import is being doing for side-effects but not being named. Therefore:The one "edge case" is that if the default export of the module being something that gets erased (is that even possible to export default something that is erasable)?
aluanhaddad commentedon Jun 17, 2016
@markrendle for what it's worth, this is my pattern for registering services in angular 1.x:
my-service.ts
my-other-service.ts
app.ts
main.ts
This ensures the service import will not be elided. It also has the advantage of decoupling your service classes from angular (sure $inject is there but they don't depend on angular).
Edit: Updated example with explicit export from "app.ts"
ThatRendle commentedon Jun 22, 2016
Aluan Haddad (@aluanhaddad) I see what you've done there, but I use ngAnnotate as part of my build process so I don't have to manually maintain
$injectproperties, and I don't think ngAnnotate would pick up that way of adding services... although I'll give it a try.This would all go away if my boss would just let me spend 6-9 months rewriting the entire application in Angular 2...
aluanhaddad commentedon Jun 22, 2016
@markrendle I don't use ngAnnotate so I wouldn't know if that would work but the only reason I write my "services" as classes registered with
.serviceinstead of factories registered with.factoryis to take advantage of the static inject notation. That said, I only used the above style for my example because it is my preference.My example was just meant to show that you don't have to register each service in the module where it is defined. I also think that there are compelling reasons to avoid doing so.
Regardless, using a tool like ngAnnotate shouldn't dictate the way in which you structure your code or the order in which you register your services.
ThatRendle commentedon Jun 22, 2016
Aluan Haddad (@aluanhaddad) But it does, because it makes life so much easier that I'm willing to put up with its demands.
63 remaining items
karianpour commentedon Jun 9, 2019
So, any work around?!
swar30 commentedon Jun 9, 2019
Kayvan Arianpour (@karianpour), to the original issue in this thread yes, just do double import once of the type and once just of the module with no types, look at the start of the thread for details
Preserve all typescript imports, not only .svelte
whzx5byb commentedon Oct 28, 2019
I use
export * from './MyService'where myservice.ts exports default likeexport default class MyService {}.It doesn't reexport anything but it do force to execute the side-effect codes.
If you use barrel files(index.ts which re-exports module), every file must export an empty default value as below, to prevent tree-shaked by ts compiler.
index.ts
PS: I prefer
export * from './MyService'rather thanimport './MyService'because the former reports a error path while the latter doesn't.viT-1 commentedon Oct 29, 2019
In MainFilter.ts I use import
{ conf, IData } from './MainFilter.conf';and in dev-mode for browser use<script type="module">MainFilter.conf.ts has interface IData:
In browser console I have an error:
Uncaught SyntaxError: The requested module './MainFilter.activity.conf.js' does not provide an export named 'IData'cause of tsc cutting out interface export from MainFilter.conf.js =(
How to solve it? Why MainFilter.js not cutted out IData?
viT-1 commentedon Oct 29, 2019
Solved as
but forced to off import/no-duplicates rule =(
andrewbranch commentedon Nov 27, 2019
FYI, I have a PR open to fix this at #35200. Feedback is welcome from anyone still interested in this issue. Thanks!
lgarron commentedon Apr 27, 2021
This keeps tripping me up, so I thought I'd note it here.
This code breaks when the
elem2line is commented out:Unfortunately, I find this is a pretty common situation when working with custom elements, and as a library author I'm frustrated that I can't fix this for library users. It also makes it trickier to recommend TypeScript to beginners. The only way to allow
elem2to be commentable in the code above is to change the imports to the following, which I think should be considered an anti-pattern (I would flag it in a code review):Given that TypeScript will probably treat
import ClipboardCopyElementlikeimport type ClipboardCopyElementin the foreseeable future, it would still be really useful to have "import with side effects" (ideally still compatible with normal JS syntax). This:(Ideally, I'd love to have tooling that encourages the use of
import typewhen possible, and keeps ESM semantics forimporting objects.)Bart76 commentedon Apr 27, 2021
Lately my eye caught a compiler/tsconfig option called
importsNotUsedAsValueswhen I was browsing the TSConfig Reference on the TypeScript website. Perhaps this issue here is solved when specifying the valuepreserveorerrorfor that option?[tsconfig.json] Enforce that type-only imports must be used with `imp…
richardkazuomiller commentedon May 11, 2021
Sorry if I'm confused about why this is closed. This hasn't been fixed, has it?
It would be nice to have something that is the opposite of
import typethat tells TypeScript we want to actually import the file, even if the things we're importing just so happen to be types.Right now, we have to do this:
Is there a way to shorten this? If not, maybe something
import typeindicates we only care about these imports in type space, andimport valuetells TypeScript that there is something infile.tsthat we need in value space.jods4 commentedon May 11, 2021
Ricky Miller (@richardkazuomiller) I think you want to set the option
importsNotUsedAsValues: preserveWith this, all your imports will be kept, only explicit
import typewill be removed.richardkazuomiller commentedon May 11, 2021
jods (@jods4) Thanks, that looks like it might do the trick 😄
Add registerall, clean up exports