-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
define parameter not generated for a referenced AND used external module class. #2038
Comments
There is no reason, if you are calling an instance method of an imported TS class, that the associated import statement should not be processed in the compiled code. The problem here is that you aren't calling an instance method of an imported instance. From the type system's perspective all you have done is used the type of an imported class. The compiler has an optimization to not emit imports for modules that are only used for type information (since then they're unneeded at runtime and would only cause a performance impact). Obviously here that's biting you (you are not the first ex #596). Unfortunately the compiler is unaware of the Angular magic that causes this module to actually get loaded because of its use in this parameter position. Your options are the workaround you found or to use the |
@danquirk - I have declared a parameter of an imported type and then USED the parameter of that type with the instance method call I can see optimizing away type information that is not necessary at run time but in this case, clearly the module needs to be imported for it to function. Are you absolutely sure it is not possible for a compiler to determine if a call to an instance method of an imported type has been made and if so, load the module? Why so quick to close the issue without discussion? |
A solution for this problem is the new ES6-style |
@mhegazy - Thank you for replying with a solution. I think I documented pretty well a valid scenario where a I look forward to seeing this feature added. |
I do not see how the compiler would do that. remember types are not nominal, they are structural in TypeScript. So we have no way of knowing that this specific type is something that requires the module to be loaded, or it is just a structural type that you gave it a name and put it in that module because you do not want to redefine it. The flip side is if we add an import to one of these type-only modules we will be requiring a file that does not exist at run time. |
@mhegazy - I appreciate you time on this. It sounds like you are saying that the module that I am referencing could/might only contain a type definition, similar to a .d.ts file, and therefore it assumes that it should not create the appropriate define. Where this is difficult to follow, is the fact that I am calling a method on a type, which not only has a type definition (structure), but there is actual code in that module that the compiler must actually process/build and output. In my layman mind, if the compiler actually builds and outputs type A in external module X then the compiler should be tracking that type A is not just a structure but an actual class. If Type B uses an instance of Type A in external module X, then the fact that code was generated and written for X would serve as the indicator that external module X must have a define created for it when imported. More confusing is the fact that calling Perhaps I am expecting too much in trying to compare C# compilation to JavaScript compilation. There's probably a good reason why the compiler does not make the same assumptions that I do, I just don't know what it is. This is probably a good topic for a blog article. |
The compiler has only one rule for determining whether or not to emit a module import: was the imported name used in a value position. This encodes the assumption that module imports don't have side effects. Anything in the type system has no effect on that. We have an important scenario here where you get the type information from an external module but don't actually import it 100% of the time, which is what it "looks like" to the compiler. |
@danquirk It's an arbitrary and dangerous thing to have the TypeScript engine take on the responsibility of optimizing the import statements. There are many patterns that TypeScript does not yet capture from JavaScript. One example is how it does not address that Import is used to load dependencies before the current code is loaded and may not be referenced directly. Angular dependencies are one example, while jQuery plugins are another. Any library that extends a base object and is not referenced directly are affected by "feature". By deciding to arbitrarly not included an import based on local static analysis you are imposing a C style compiler pattern over the explicit intention of the developer who wrote the import statement. The expectation of writing import is that it will be included as a dependency and available to the local scope of the module. Any other action is a side effect to the natural expectation of choosing to write It is very possible that in this case the TypeScript compiler could do less, and accomplish more. |
It is not arbitrary. It's entirely reasonable for someone to import a module only for type information and not want to bear the cost of loading code that won't be used, or the module may only be type information and there actually is no code to load at all (and attempting to load it will fail at runtime, as @mhegazy described). Yes the compiler could choose to always emit imports and this case would work correctly. Other cases would then work incorrectly. There are always trade offs. We want this scenario to work and we do/will have multiple ways to do that now (amd-dependency, ES6 style import "mod"). |
It's arbitrary because there is a way to load a module for its type information and have it added to the scope of TypeScript "intellisense" In my example the expectation is that the file will be loaded, as the file has compilable contents, hence the need for them as a dependency. This is the existing usage, pattern, and expectation of the CommonJS and AMD (Require.js) implementation in node and client side JavaScript libraries. Your premise is that the compiler needs to optimize because someone could be linking to something that has no output. This is exclusively a TypeScript behavior, and linking to files for contextual information is already addressed in the spec (see The issue in your last paragraph only occurs because (original bug #2132) |
I am using AngularJs and injecting a service, which is a TypeScript class in an external module, into a controller which is also a TypeScript class. Though I am specifically making a call to a service method, the TypeScript compiler will not include the external module in the define function unless I have a JavaScript call to
moduleVariable;
There is no reason, if you are calling an instance method of an imported TS class, that the associated import statement should not be processed in the compiled code.
Service TS Definition
Controller TS Definition
Generated Controller JS (define is missing dataAccessServices/PurchaseOrder.service)
"Fixed" Controller (TSLint says "expected assignment or function call")
"Fixed" Controller JS
The text was updated successfully, but these errors were encountered: