I had some issues with destructuring assignment shorthand when auto formatting JavaScript and TypeScript code in Visual Studio Code.
I got result like this:
var {
check,
validationResult
} = require("express-validator/check");
but I need it to looks like this:
var { check, validationResult } = require("express-validator/check");
I have Beautify installed, and in my settings:
{
"editor.wordWrapColumn": 160,
"typescript.format.placeOpenBraceOnNewLineForFunctions": false,
"typescript.format.placeOpenBraceOnNewLineForControlBlocks": false,
"javascript.format.placeOpenBraceOnNewLineForFunctions": false,
"javascript.format.placeOpenBraceOnNewLineForControlBlocks": false
}
I don't find anywhere else I could set place new line to false.
Any idea how to set it right?
I notice this problem may resolve by changing the file extension when React component involved.
For example:
*.js -> *.jsx
*.ts -> *.tsx
Visual Studio Code seems to have trouble to format JSX when it's in the wrong type of file.
ESLint and "JavaScript and TypeScript intelliSense" extensions seems also don't like it.
Webpack works no matter what.
Related
I am using TypeChecker from the TypeScript Compiler API in order to extract (inferred) type information for every node in the AST of my program. In particular, I try to find out the return values from imported module functions such as:
var vec3 = require('gl-matrix/vec3')
var myVec = vec3.fromValues(1, 2, 3) // $ExpectedType vec3
This works well for modules that were imported using the import { … } from '…' statement, but unfortunately, modules that were imported using require() like above are not recognized correctly, I only receive the type any for them. However, I have set both compiler options allowJs and checkJs.
Why are the types form require()d modules not inferred correctly? VS Code (which AFAIK relies on the same API?) is able to infer the types from require() statements as well, so I'd guess that in general, tsc is able of handling them. Are there any other compiler options that I need to set differently? Or is this indeed not supported and I need to use some other package for this?
Here is a minimum script to reproduce, I have also put it on repl.it together with two example files: https://replit.com/#LinqLover/typecheck-js
var ts = require("typescript")
// Run `node index.js sample-import.js`` to see the working TypeScript analysis
const files = process.argv[1] != "/run_dir/interp.js" ? process.argv.slice(2) : ["sample-require.js"]
console.log(`Analyzing ${files}:`)
const program = ts.createProgram(files, {
target: ts.ScriptTarget.ES5,
module: ts.ModuleKind.CommonJS,
allowJs: true,
checkJs: true
})
const checker = program.getTypeChecker()
for (const sourceFile of program.getSourceFiles()) {
if (!sourceFile.isDeclarationFile) {
ts.forEachChild(sourceFile, visit)
}
}
function visit(node) {
try {
const type = checker.getTypeAtLocation(node)
console.log(checker.typeToString(type))
} catch (e) {
// EAFP
}
ts.forEachChild(node, visit)
}
Thank you so much in advance!
For follow-up, this turned out to be an issue with the type definitions for gl-matrix. I should better have tried out multiple packages before suspecting that the TypeScript engine itself could be broken ...
gl-matrix issue: https://github.com/toji/gl-matrix/issues/429
My compiled Babel output tries to import a function/file that does not exist. Am I missing a configuration or step in my Mix/Babel/Webpack configuration that would output this file?
I am using Laravel Mix (5.0.4) with its default configurations.
I've recently used the Javascript await operator for the first time. It is causing an issue with Babel. When Babel processes await to make it backwards compatible, it adds import _regeneratorRuntime from "#babel/runtime/regenerator"; to the beginning of the Javascript file. However, babel/runtime/regenerator doesn't actually exist. This causes the Javascript to fail when the browser attempts to load it, producing the error Error resolving module specifier: #babel/runtime/regenerator.
I am beyond my understanding of how Mix, Babel, and Webpack work together. I do not know how to tell Mix/Babel/Webpack to produce file(s) that contain the necessary module(s), or if there's something else I need to be doing.
I've tried many solutions via googling, played with the configuration files, and hit my head against my desk a bunch of times. None of these worked. I'm not sure if I am even asking the right questions.
Debugging info:
webpack.mix.js looks like this:
const mix = require('laravel-mix');
// Use of mix.babel() is imperative as this is legacy code and cannot leverage mix.js()
mix.babel('public/js/helpers.js', 'public/js/processed/helpers.js')
.babel('public/js/main.js', 'public/js/processed/main.js')
.babel('public/js/stripe.js', 'public/js/processed/stripe.js');
The problematic Javascript looks like this:
function foo() {
const bar = document.getElementById('bar');
bar.addEventListener('click', async (event) => {
// ('async' is the part which causes the `import` to be added)
});
}
And when run through Babel, looks like this:
import _regeneratorRuntime from"#babel/runtime/regenerator";function asyncGeneratorStep(n,e,r,t,o,a,u){try{var c=n[a](u),i=c.value}catch(n){return void r(n)}c.done?e(i):Promise.resolve(i).then(t,o)}function _asyncToGenerator(n){return function(){var e=this,r=arguments;return new Promise(function(t,o){var a=n.apply(e,r);function u(n){asyncGeneratorStep(a,t,o,u,c,"next",n)}function c(n){asyncGeneratorStep(a,t,o,u,c,"throw",n)}u(void 0)})}}function foo(){document.getElementById("bar").addEventListener("click",function(){var n=_asyncToGenerator(_regeneratorRuntime.mark(function n(e){return _regeneratorRuntime.wrap(function(n){for(;;)switch(n.prev=n.next){case 0:case"end":return n.stop()}},n)}));return function(e){return n.apply(this,arguments)}}())}
When I dig into Mix's default Babel config, I think it's using this:
{
cacheDirectory: true,
presets: [
[
'#babel/preset-env',
{
modules: false,
forceAllTransforms: true
}
]
],
plugins: [
'#babel/plugin-syntax-dynamic-import',
'#babel/plugin-proposal-object-rest-spread',
[
'#babel/plugin-transform-runtime',
{
helpers: false
}
]
]
}
Use js mixin instead:
const mix = require('laravel-mix');
mix.js('public/js/helpers.js', 'public/js/processed/helpers.js')
.js('public/js/main.js', 'public/js/processed/main.js')
.js('public/js/stripe.js', 'public/js/processed/stripe.js');
I was not able to find a working solution in a reasonable time for the legacy project I was working on, so I just used a workaround and documented it. I tried various solutions, different libraries and compilers, upgrading existing libraries, better workarounds and so on. Because this was a legacy project, most changes/updates/tool swaps resulted in a cascade of changes needed (and it still didn't work in the end after making all of those changes).
Ultimately, all I did was take the offending bit of Javascript (it was only one small function) and moved it to its own Javascript that does not get processed by Babel.
// The code that gets processed fine is here:
mix.babel('public/js/stripe.js', 'public/js/processed/stripe.js')
// The code that doesn't get processed without error is here:
.copy('public/js/stripeUnminified.js', 'public/js/processed/stripeUnminified.js');
Considering the time I had invested, this workaround was an ok solution. Running the offending bit of Javascript through a compiler such as Babel just wasn't actually a super critical priority considering all of the headache it was causing and time it was taking. It was looking like I was going to have to rework and update a lot of the project just to fix this one little problem (and still a fix was not guaranteed).
Unfortunately due to using cucumber and writing out scenarios I end up with incredibly long file names which windows complains about. Is it possible to override the naming for the files?
I'm assuming you're using the Nightwatch framework since you've tagged it in your post.
It looks like screenshot filenames are defined in nightwatch/lib/api/client-commands/end.js at line 26 of the latest repo const prefix = '${this.api.currentTest.module}/${this.api.currentTest.name}';.
The screenshot path is defined in your nightwatch.json:
{
"test_settings" : {
"default" : {
"screenshots" : {
"enabled" : true,
"on_failure" : true,
"path" : "./screens"
}
}
}
}
It appears your have a few options:
Modify the code in end.js to use a custom naming scheme, and live with a custom framework
Shorten your test module names or test names
Shorten your screenshot destination path in nightwatch.json - unlikely to solve anything since you're saying it's the filenames that are the problem.
This should be possible by using the filename_format option, since:
#2023 was merged
Given the following
/**
* #param {{bar?: string|null}} [param0]
*/
const foo = ({bar = null} = {}) => bar;
Typescript 3.7.2 reports
var bar: string | null
Binding element 'bar' implicitly has an 'any' type.ts(7031)
The JavaScript code works how I want it to, but how can I write the jsdoc hint so that TypeScript understands that the destructured bar variable is string|null not any?
Update with correct answer
The problem found is actually your tsconfig and how the JavaScript type checking works with it. The option that is causing the difference between your config and mine is the strict property. According to the config documentation:
Enabling --strict enables --noImplicitAny, --noImplicitThis, --alwaysStrict, --strictBindCallApply, --strictNullChecks, --strictFunctionTypes and --strictPropertyInitialization.
Adding each of those options to my tsconfig, I discovered that disabling two of those options would get rid of the reported error. Those options are:
--strictNullChecks
--strictPropertyInitialization (because it can't be enabled without the --strictNullChecks option)
When I disabled those two, it was finally happy with the result.
I copied the example into a TypeScript file to see if it had a similar problem.
The TypeScript version reported no errors with the same exact type signature, but the JavaScript version was ignoring the JSDoc altogether. However, looking at the rest of the code, it still was registering the bar variable as being of type string|null.
Coming to this conclusion, it is likely a bug in the JavaScript type checking and how it works with those options despite neither of those options seemingly being related to this case.
EDIT:
I've checked and it looks like there is a bug already logged for this on the TypeScript repo:
https://github.com/microsoft/TypeScript/issues/31372
Previous solution (which didn't work)
You should be able to do this easily. Maybe remove the square brackets from the param name in the jsdoc comment. This example works fine:
/**
* #param {{bar?: number|null}} _
*/
const foo = ({ bar = null } = {}) => {
// do stuff with bar
}
The tsconfig that I have looks like this:
{
"compilerOptions": {
"checkJs": true,
"allowJs": true,
"outDir": "node_modules/.tmp/",
"noImplicitAny": true
},
"include": [
"index.js"
]
}
Here is the repo that has this code you can use to check on your side, too:
https://github.com/cwadrupldijjit/js-typescript-checking
The version of TypeScript that this was tested in is 3.7.2
EDIT:
Checked out the square brackets vs non-square brackets and it looks like it doesn't matter. TSC is fine with it either way.
In my Node application, I have a settings file that exports some settings as an object like this:
// settings.ts
export var settings = {
port: 1234
}
In another file, I import these settings and attempt to reference the port property:
// another-file.ts
import { settings } from './settings';
console.log(settings.port);
This code compiles correctly, but at runtime I get the following error:
Cannot read property 'port' of undefined
When I inspect the compiled code, I can see that this is happening because my second file above is compiling to this:
var settings_1 = require("./settings");
console.log(settings_1.settings.port);
If I walk through the compiled code with my debugger, I can see that the settings_1 variable points to the exported value from settings.ts. In other words, my port property lives at settings_1.port, not at settings_1.settings.port. It seems the TypeScript compiler should instead generated this JavaScript code:
var settings = require("./settings");
console.log(settings.port);
Am I doing something wrong? Or is the TypeScript compiler incorrectly compiling my import?
I know that the TypeScript compiler is correctly type-checking my import; if I do something like this:
import { settings } from './settings';
console.log(settings.propertyThatDoesNotExist);
I get compiler errors that propertyThatDoesNotExist doesn't exist.
I'm using TypeScript 2.3.2, targeting "es5" and outputting "commonjs" modules, running on Node 6.9.2.
Figured it out. It was a silly mistake on my part (isn't it always?). I was working on converting an application from JavaScript to TypeScript, and I copied and renamed settings.js to settings.ts... but I didn't delete settings.js. As a result, I was actually importing my old settings.js file which had its exports set up differently.
Once I deleted settings.js, my application started correctly using the .ts file instead, and my imports worked as expected.