Using Typescript 3.* and momentjs for dates I get compile time errors.
Calls like moment() generate following error:
Cannot invoke an expression whose type lacks a call signature. Type 'typeof moment' has no compatible call signatures.ts(2349)
api.ts(9, 1): Type originates at this import. A namespace-style import cannot be called or constructed, and will cause a failure at runtime. Consider using a default import or import require here instead.
replacing moment() calls with moment.default() resolves the issue.
Im using following nswag.json
{
"runtime": "NetCore21",
"defaultVariables": null,
"swaggerGenerator": {
"fromSwagger": {
"url": "http://localhost:54408/swagger/v1/swagger.json",
"output": null
}
},
"codeGenerators": {
"swaggerToTypeScriptClient": {
"className": "{controller}Client",
"moduleName": "",
"namespace": "",
"typeScriptVersion": 3.2,
"template": "Fetch",
"promiseType": "Promise",
"httpClass": "HttpClient",
"useSingletonProvider": false,
"injectionTokenType": "OpaqueToken",
"rxJsVersion": 6.0,
"dateTimeType": "momentjs",
"nullValue": "Undefined",
"generateClientClasses": true,
"generateClientInterfaces": false,
"generateOptionalParameters": false,
"exportTypes": true,
"wrapDtoExceptions": false,
"clientBaseClass": null,
"wrapResponses": false,
"wrapResponseMethods": [],
"generateResponseClasses": true,
"responseClass": "SwaggerResponse",
"protectedMethods": [],
"configurationClass": null,
"useTransformOptionsMethod": false,
"useTransformResultMethod": false,
"generateDtoTypes": true,
"operationGenerationMode": "MultipleClientsFromOperationId",
"markOptionalProperties": true,
"generateCloneMethod": false,
"typeStyle": "Class",
"classTypes": [],
"extendedClasses": [],
"extensionCode": null,
"generateDefaultValues": true,
"excludedTypeNames": [],
"handleReferences": false,
"generateConstructorInterface": true,
"convertConstructorInterfaceData": false,
"importRequiredTypes": true,
"useGetBaseUrlMethod": false,
"baseUrlTokenName": "API_BASE_URL",
"queryNullValue": "",
"inlineNamedDictionaries": false,
"templateDirectory": null,
"typeNameGeneratorType": null,
"propertyNameGeneratorType": null,
"enumNameGeneratorType": null,
"serviceHost": ".",
"serviceSchemes": null,
"output": "src/generated/api.ts"
}
}
}
Is this a typescript version or momentjs version problem?
Actually the currently generated code seems not to be compliant with ES6.
The import statement currently used (import * as moment from "moment") is a module import, and modules are not allowed to be called (i.e. moment() is forbidden). All named exports of moment can be accesed through the importet object. The default export can be called via moment.default() (as far as I understand it)
ref1 https://stackoverflow.com/a/35706271/2017490
ref2 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
In my opinion the correct solution is to change import * as moment from "moment" to import moment from "moment". So we just import the default export and name it moment.
Where exactly do you see moment() rendered?
In the init(data?:any){} method
its not exactly moment() but moment(data["started"].toString())
started is a DateTime property in the backend

So what would be the correct code for moment(data["started"].toString()) ?
Can you create a list of what has to be changed?
I'm seeing this issue as well (targeting TypeScript 3.2.2 in my application, NSwag is told to use 2.7 as that is the latest option available). I don't know about any backwards compatibility issues that this change might cause, but simply changing import * as moment from 'moment'; to import moment from 'moment'; makes the errors further down with e.g. moment(data["started"].toString()) go away.
I'm using moment version 2.23.0 FYI
agree changing to import moment from 'moment'; should solve and should also be backwards compatible
I've figured out where this issue comes from. In your tsconfig.json, you might have this property set:
"allowSyntheticDefaultImports": true,
This apparently causes the TS compiler error. I don't know if NSwag should do anything to fix this or not, but removing that entry (or setting it to false) got rid of the error for me.
I can confirm that setting allowSyntheticDefaultImports: false resolve the issue.
Unfortunatly there is a reason I had set it to true (some other library I am depending on has a weird export definition).
As the currently generated code does not seem to adhere to es2016 I would vote to implement the changes.
So we need to just change the import to
import moment from 'moment';
here:
and this is backward compatible and not a breaking change for anyone?
BTW: You can already override this template: https://github.com/RSuter/NSwag/wiki/Templates
I've created a PR: https://github.com/RSuter/NSwag/pull/1901
Can you confirm that this will not break existing users?
This is not a backwards compatible upgrade that I can tell. If your tsconfig.json contains the following, you must do the import moment from 'moment'; default import workflow:
{
"compilerOptions": {
...
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
...
}
}
If you don't have the "allowSyntheticDefaultImports", the default import won't work at all, and you'll continue to have to use the import * as moment from 'moment';
I can provide you a sample with more details if that helps. I have a suitable workaround for my project (I don't require the two options noted above). If you do decide to go forward with the change, at least the upgrade path is pretty easy.
I've attached some screenshots that I hope help:
With the above options, import * error:

Without the above options, default import error:

And in case you're interested, my dependencies for the reproductions:
"dependencies": {
"moment": "^2.23.0"
},
"devDependencies": {
"typescript": "^3.2.4"
}
I tried to test against Typescript 2.9.2 and Typescript 2.7.2.
In Typescript 2.9 I could compile, however users with "allowSyntheticDefaultImports":"true" would indeed be broken.
I couldnot test against 2.7 or older versions, as I get a lot of other errors (tsc checks node_modules, and many configs in tsconfig don't work).
What I also tested is leaving the import * as moment from "moment" as is and instead changing the moment(xxx) calls to moment.default(xxx). This unfortunatly also does not work with Typescript 2.9 (works with Typescript 3.*)
Based on the above observations its maybe better to think about other alternatives.
Any progress with this issue? as a workaround i now disabled "importRequiredTypes" and added extensioncode for the imports by hand
The question is how we should solve this without breaking existing users? Do we need a new setting (i try to avoid that)?
@RicoSuter What about reading the tsconfig.json and tweak the import depending on allowSyntheticDefaultImports?
I think that's not a good idea because we dont want to couple this to tsconfig.json (its also not part of the configuration etc.) maybe we should just add a AllowSyntheticDefaultImports setting to the TypeScript generator?
I have temporarily fixed this by replacing the import with import moment from 'moment-es6'; and adding that to my packages. Dependencies appear to require es6 modules for angular libraries which is where I have placed my service-proxies.ts because two separate applications consume it (angular monorepository structure).
I don't know if this is the ideal solution (I spent hours trying to figure out how to get moment.js to work in an Angular library with no success) but it would be nice to have a boolean in the config to tell the generator to use the moment-es6 package so I don't have to remind myself and my team to update it.
You can replace the file template with one with te correct import but probably we should support that with a simple setting.
https://github.com/RicoSuter/NSwag/wiki/Templates
I also have angular 8 project (ts 3?) and i dont have problems with momientjs
I also have angular 8 project (ts 3?) and i dont have problems with momentjs
Can you generate a library ng g library <LIBRARY_NAME> and place your existing service-proxies.ts under projects/<LIBRARY_NAME>/src/lib and let me know if it compiles for you? I had issues with it but it's possible I messed something up.
in my way, just disable
esModuleInterop in tsconfig.json
in my way, just disable
esModuleInteropintsconfig.json
work
Hi just adding my input as its Oct 2020 and this is still open.
From MY experience, NO NEED to disable esModuleInterop in tsconfig.json _(as answer before mine suggests)_
All I did was change the following import statement which caused the compilation error:
import * as moment from 'moment';
to
import moment from 'moment';
In my tsconfig.jsonthe following options which i added myself are still set to _true_:
{
"compilerOptions": {
...
"esModuleInterop": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
...
}
}
(Also ran npm audit fix before compiling - _which we tend to ignore_)
Don't forget to stop app and run npm installagain (just for extra measures).
Hope this helps 馃憤
(BTW my local project is running: "@angular/cli": "9.0.1" and "typescript": "3.7.5")
Most helpful comment
Actually the currently generated code seems not to be compliant with ES6.
The import statement currently used (
import * as moment from "moment") is a module import, and modules are not allowed to be called (i.e.moment()is forbidden). All named exports of moment can be accesed through the importet object. The default export can be called viamoment.default()(as far as I understand it)ref1 https://stackoverflow.com/a/35706271/2017490
ref2 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
In my opinion the correct solution is to change
import * as moment from "moment"toimport moment from "moment". So we just import the default export and name it moment.