How to change the default import hint in VSCode from ES6 to commonjs? - typescript-typings

I've a small piece of JavaScript that I open on Visual Studio Code, I then enable #ts-check to get type hinting from TypeScript definition files.
When I refer to a type that comes from a different import VSCode will give the hint and add the following code to the beginning of the file:
import { SomeType } from 'some-module';
This is correct if I'm working on ES6 but currently I'm targetting to older runtimes and would prefer to get the generated code be written using the commonjs syntax:
var SomeType = require('some-module').SomeType;
Is there any configuration I can change to achieve this behavior?

I'm in a similar situation. I've been able to get rid of type errors but I can't seem to figure out how to get code completion to list 'require' or 'module.exports' in its options.
To get ride of type error messages.
{
"compilerOptions": {
"module": "commonjs",
"target": "es2015"
},
"exclude": ["node_modules"]
}

Related

Disable DOM library type definitions in nodejs project VSCode

I want to disable DOM type definitions in a Node.js TypeScript project. I have configured TypeScript using the configuration shown in the snippet below. Despite explicitly setting the "lib" property to ["ES2016"], VS Code continues to suggest lib.dom.d.ts auto completions. The project seems to pull the definitions from the lib.dom.d.ts definition file that resides in VS Code (specifically the ~/.vscode/extensions directory, rather than from the node_modules directory. The end result seems to be a runtime error. Obviously Node.js has no use for the DOM library; is there some means for disabling the DOM library?
Using the configuration below (as stated above) does not work.
{
"compilerOptions": {
"lib": ["ES2016"],
"target": "es6",
"module": "commonjs",
"skipLibCheck": true,
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"allowJs": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"inlineSourceMap": true,
"importHelpers": true,
"alwaysStrict": true,
"strict": true,
"outDir": "build",
"forceConsistentCasingInFileNames": true,
"esModuleInterop": true,
"typeRoots": ["./node_modules/#types", "./typings"],
"baseUrl": ".",
"paths": {
"#root/*": ["./*"]
}
},
"include": [
"src/**/*",
"__tests__/**/*",
"config/**/*",
"scripts/bundle-test.ts"
],
"exclude": ["node_modules"]
}
It is impossible to tell you how to configure your project in a way where you specify libraries that you wish to exclude. This is because TypeScript doesn't support any such mechanism in its tsconfig.json file for doing so. To know how to not include the DOM, you need to know how to configure your project to use, rather, that NOT-USE, ECMAScript libraries & standards.
When defining which ECMAScript libraries to include in your schema-defined tsconfig.json file, you need to consider two settings.
       The 1st being: "noLib": string[],
          and the 2nd: "lib": string[],
Rarely is noLib the Best Option to Use
Setting noLib to true is rarely necessary. When used (or set to true) the project will not auto-import libraries, many that you will have to import every single library, and type-definitions for those libraries, that you want to use. Now, this can be used to define everything you want, and leaving out everything like the DOM library that you don't want.
Typically Lib Will be the More Practical Property
Lib works by defining the ECMAScript Libraries that you want to be able to use.
"This question is specific to Node.js, and therefore, I will answer it as such" Typically with Node.js you can set lib to any recent version of the ECMA-262 Standard (aka ECMAScript) and be okay. The same is not true for JavaScript running in the browser. With Node.js you get a single controlled Runtime Environment, only ever used by those with programming experience. The browser, well you get every walk of life, and users who execute your code in VT terminals (okay, maybe not a real VT, but u get what I mean).
The ECMAScript Standards that you can assign as a value to the tsconfig.json "lib": [] property, are listed below in order of age (oldest --> newest).
"ES5"
"ES6"
"ES7",
"ES2015"
"ES2016"
"ES2017"
"ES2020"
"ES2019"
"ES2021"
"ESNext"
Side note on noLib again.
Since I took the time to compile this list, I figure I might as well offer it for noLib too. As I disclosed to you above, the tsconfig.json property noLib means you don't want any Libraries included by any version of the ECMA-262 standard, and you, yourself want to define, on an individual basis, which libraries that will be included (this also means you need to provide type information (see below for getting types). Below are the libraries you can define one-by-one.
!Please Note: For reasons beyond the scope of this answer, there are situations where using noLib to define a projects ECMA-Feature support can be UN-avoidable. And you must painstakingly list each feature, the standardization to use for the feature, and you must include, and properly configure, the types for each one you add.
"The libraries below are added to lib when noLib is set to true".
Using the libraries below, is the only way to be specific about the libraries you use. Even then, you still are not specifying what not to use though. So you cannot use this method to specifically "NOT USE DOM".
"ES2015.Collection",
"ES2015.Core",
"ES2015.Generator",
"ES2015.Iterable",
"ES2015.Promise",
"ES2015.Proxy",
"ES2015.Reflect",
"ES2015.Symbol.WellKnown",
"ES2015.Symbol",
"ES2016.Array.Include",
"ES2017.Intl",
"ES2017.Object",
"ES2017.SharedMemory",
"ES2017.String",
"ES2017.TypedArrays",
"ES2018",
"ES2018.AsyncGenerator",
"ES2018.AsyncIterable",
"ES2018.Intl",
"ES2018.Promise",
"ES2018.Regexp",
"ES2019.Array",
"ES2019.Object",
"ES2019.String",
"ES2019.Symbol",
"ES2020.BigInt",
"ES2020.Promise",
"ES2020.String",
"ES2020.Symbol.WellKnown",
"ESNext.Array",
"ESNext.AsyncIterable",
"ESNext.BigInt",
"ESNext.Intl",
"ESNext.Promise",
"ESNext.String",
"ESNext.Symbol",
"DOM",
"DOM.Iterable",
"ScriptHost",
"WebWorker",
"WebWorker.ImportScripts",
"Webworker.Iterable",
"ES2020.SharedMemory",
"ES2020.Intl",
"ES2021.Promise",
"ES2021.String",
"ES2021.WeakRef",
"ESNext.WeakRef",
"es2021.intl"
LIBRARY TYPES CAN BE FOUND #
TypeScriptLang's Type-search App - Easy to use app
NPM via search for types - Its NPM...
Definitely-Typed GitHub Repo This isn't as easy to navigate as the other two options, but its cutting out the middle man. This is where NPM & TypeScriptLang's app get most of their types from.

Typescript configure mapping for compiled import path

I have an aws amplify project which is using yarn workspaces.
My project has a lambda function and a layer. When the lambda function runs in aws it needs to import my library from the layer...
import MyLib from '/opt/nodejs/build/MyLib';
However when I run this function locally I want to import the library from my local file system
import MyLib from '/Users/sive/Documents/SWT/wake-book/amplify/backend/function/wakebookLayer/lib/nodejs/build/MyLib';
How can I tell typescript to compile an import from /opt/nodejs/build/MyLib to the location on my local file system.
I tried using path mapping in my tsconfig.json
"baseUrl": ".",
"paths": {
"/opt/nodejs/build/MyLib": ["./amplify/backend/function/wakebookLayer/lib/nodejs/build/MyLib.d.ts"]
},
This stops vscode complaining about an unknown import, so it is being 'linked' correctly (I can cmd click my import /opt/nodejs/build/MyLib path and I am taken to the full file system path.)
But the compiled js is still using the wrong path.
The compiled js file looks like this
const MyLib_1 = __importDefault(require("/opt/nodejs/build/MyLib"));
I would expect it to remap the import path and to look like this
const MyLib_1 = __importDefault(require("/Users/sive/Documents/SWT/wake-book/amplify/backend/function/wakebookLayer/lib/nodejs/build/MyLib"));
If I manually edit the output js to have the full file system path it works (I can run my project locally).
Have I misunderstood how path mapping is supposed to work?
Is there a way to get my desired behaviour?
Updated edit: I don't think this has anything to do with the fact that the path itself is long or complex. I'm having trouble getting mine to pass through correctly as well. I think the issue has to do more with how you're (and I'm) implementing the path mapping itself.
To test this theory, you could move one of those dependencies to a very simple, short path and see if that has any impact on the behavior at all.
Edit: I'm sorry, I just realized that you were trying to do this earlier and the problem seems to be related to the path itself... I'm not sure this will be helpful at all, but I'm going to leave it here for reference for now. I'm quite happy to try to address this with you over comments/edits.
What you are looking for is called "Path Mapping". There are a few ways this might be handled depending on your project. If you're deploying via SAM, this article from AWS describes one possible solution: https://aws.amazon.com/blogs/compute/working-with-aws-lambda-and-lambda-layers-in-aws-sam/
The important excerpt from that is here:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: sam app
Globals:
Function:
Timeout: 3
Runtime: nodejs8.10
Resources:
TempConversionFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: hello-world/
Handler: app.lambdaHandler
Events:
HelloWorld:
Type: Api
Properties:
Path: /{conversion}/{value}
Method: get
This change dropped out some comments and output parameters and
updated the function resource to TempConversionFunction. The primary
change is the Path: /{conversion}/{value} line. This enables you to
use path mapping for our conversion type and value.
I've also seen examples that leverage tsconfig, but this seems to be a separate solution. Again, here is a link to the documentation: https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping
And the relevant excerpt:
Sometimes modules are not directly located under baseUrl. For
instance, an import to a module "jquery" would be translated at
runtime to "node_modules/jquery/dist/jquery.slim.min.js". Loaders use
a mapping configuration to map module names to files at run-time, see
RequireJs documentation and SystemJS documentation.
The TypeScript compiler supports the declaration of such mappings
using paths property in tsconfig.json files. Here is an example for
how to specify the paths property for jquery.
{
"compilerOptions": {
"baseUrl": ".", // This must be specified if "paths" is.
"paths": {
"jquery": ["node_modules/jquery/dist/jquery"] // This mapping is relative to "baseUrl"
}
}
}
Without knowing more about how you deploy your code, it's not possible for me to give more a more exact answer. But I hope this helps.
I should note, that your try/catch block does work, but it wouldn't be considered a best practice.
It's been a year and a half since this post was first answered, and there still doesn't seem to be a widely publicized solution to this issue.
So in case anyone stumbles upon this, here's what I came up with:
I have a JAVASCRIPT (.js, not a .ts file) in all my lambda function handler directories whose single responsibility is to import the layer, at run time, from the appropriate path (at either the '/opt/nodejs' path or the local path on my computer). It does so using a try/catch mechanism, which I know is a sort of anti-pattern, but it works well for this scenario.
try{
module.exports = require("/opt/nodejs/index")
} catch {
module.exports = require("../../layer/index"); // my local path
}
Then, in my handler code I import the layer with this code snippet:
import layer = require("../../layer"); // path to aforementioned file
This solution is leveraging an obscure typescript feature referred to as 'export = syntax'
https://www.typescriptlang.org/docs/handbook/modules.html#export--and-import--require
It only works if the file that imports the switching layer code is a javascript (.js) file. It doesn't work if it's a typescript (.ts) file. So you'll also have to configure your tsconfig.json file with "allowJs": true

How to use existing javascript files in typescript files?

I have existing project in nodejs + express in javascript. Currently everything is working on es5.
Now i added typescript in same project and i want to do all the new development in typescript. But i am facing a issue in accessing existing javascript files.
I found that i can create definition file xx.d.ts (not sure if it is correct approach) of each existing javascript file and then use it in typescript files.
For example i have javscript file
myFile.js
function myClass(){
//some functions here associated with this variable
}
exports.myData = new myClass();
now i want to use it in my new ts file
So what i did in ts file to access is
declare function require(path: string): any;
var auth = require('./myFile').myData;
I am not sure if this is the right approach. Secondly i tried with myFile.d.ts file as well.
I defined this file in following way
declare module './myFile' {
export var myData: any
}
But this gives error of relative path -
TS2436 ambient module declaration cannot specify relative module path
Please let me know if anybody has any idea to resolve this problem or suggest if it is okay to go with first approach.
I found the solution long back but didnt posted here. Let me add the answer here so that it can help everyone
Make changes in tsconfig.json. Most important part here is types and typeRoots properties
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"sourceMap": true,
"declaration": true,
"moduleResolution": "node",
"types": ["node"],
"typeRoots": ["node_modules/#types"],
"lib": [ "es2015","dom" ]
}
}
Now go to you package.json and add some type definition packages on the basis of need
"#types/node": "~8.0.54",
After this configuration, nobody will get error and we dont need to separately specify declaration in each file

Intellisense for AMD / Requirejs in Visual Code

Is it possible to get Intellisense working in Visual Code when using AMD modules?
I have my jsconfig.json file set to:
{
"compilerOptions": {
"target": "es5",
"module": "amd"
},
"exclude": [
"node_modules"
]
}
This isn't working. I've searched everywhere but can't find how to do it.
If anyone else comes across this problem, I resolved it by changing the way I defined the modules.
From this:
define(['jquery'],
function ($) {
to this
define(function (require, exports, module) {
var $ = require('jquery');
Visual Code seems to be able to bring the Intellisense in when using the require method rather than passing an array of dependencies.
I attempted to fix this by adding comment references for the required modules.
/// <reference path="some-module.js" />
some-module.js:
var module = {
member : {}
};
define([], function(){return module;});
This allows the intellisense to function because of the missing parameter, but certainly won't run:
/// <reference path="some-module.js" />
require(['some-module'], function(){//<--no parameter "module"
module.member;//intellisense works
});
This breaks the intellisense due to hiding, but will actually execute:
/// <reference path="some-module.js" />
require(['some-module'], function(module){//<--parameter "module"
module.member;//no intellisense
});
I suppose for now I can delete the parameter while I work on the file and then restore it when I'm done. It feels like a terrible solution. If there was away to turn off the default hiding behavior or to specify that the parameter was the same as the referenced type...
Require Module Support provides good Intellisense for AMD / Requirejs if configured correctly.

Typescript seperate files for internal modules VSCode vs WebStorm

I am writing a NodeJS application and am having some problems with my editor.
Is there a reason the following works in WebStorm but not VSCode?
Edit: I didn't realize this first as I was quickly testing it, WebStorm's intellisense finds the class, but then the compiler fails and says it can't find it.
// one.ts
module Core.Routes {
export class BaseRoute {}
}
// another-one.ts
module Core.Routes {
class User extends BaseRoute {}
}
I am trying to organize my code so that I can store routes in different files,
but still inherit features from the base route.
In WebStorm this works fine, however in VSCode it is unable to find the module.
Is there something I have to do differently for VSCode?
I am basing it on the example in the video here.
In the video Visual Studio is being used, but I am on Linux and I really want to give VSCode a shot.
I have the following as my tsconfig.json:
{
"compilerOptions": {
"module": "commonjs",
"noImplicitAny": true,
"target": "ES5",
"sourceMap": true
}
}
I'm not sure what you're trying to do. In Node every file is a module. So you can't really specify the same module across files like that. Even if Webstorm intellisense can find the class name, the actual code wouldn't work. It's different from front-end Typescript
This would be a working solution:
//baseRoute.ts
export class BaseRoute {}
And then
//user.ts
import {BaseRoute} from "./baseRoute"
class User extends BaseRoute{}

Resources