is it possible to use ES2020 in tsconfig instead of coomonjs in nodejs project. Because when I use commonjs typescript when compiled generates a lot of javascript.
ES2020 and commonjs pertain to different things when configuring your tsconfig.json
ES2020 will go in the lib array. It refers to which language features to include.
commonjs will go in the module property. This refers to which module system you are using (ie. are you using require and module.exports syntax (commonjs), or import and export syntax (esm)?).
Related
In the typescript compiler options #module we've a bunch of options including nodenext and esnext, where nodenext is experimental (as of now).
Why we need this additional nodenext option when the esnext option seem already working with node.js?
Or rephrased in other words, what is the difference between nodenext and esnext?
module and moduleResolution
The first thing that needs clarification is the difference the module and moduleResolution compiler options. The former is an emit setting: what module-related code will tsc be willing to emit to JS? The easiest way to see the effect of this option is by toggling between settings commonjs and esnext:
Input code
Output --module commonjs
Output --module esnext
import { createSourceFile } from "typescript"
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const typescript_1 = require("typescript");
import { createSourceFile } from "typescript"
While this setting fundamentally controls emit, it can impose limitations on what module-related input code is allowed. For example, you cannot write imports in the style of import fs = require("fs") under --module es2015 (or higher ES targets) because there is no require to speak of in the ES module system. Additionally, using top-level await is only allowed in --module es2022 (or higher) or system because it requires corresponding support in the module loading system.
On the other hand, --moduleResolution is all about the algorithm used to answer the question “given a file system and some input file containing an import from "lodash", what files should I look for to find that module?” Obviously, the decision to look in a folder with a magical name node_modules is one related to Node (albeit one that a huge amount of non-Node tooling has copied for convenience), and is not going to be correct for every possible runtime.
Differences in moduleResolution
With this context, we’re ready to begin answering your question directly. The biggest, most noticeable difference between --module nodenext and --module esnext is that the former implies --moduleResolution nodenext, a new resolution mode designed for Node’s specific implementation of co-existing ESM and CJS, while the latter does not imply a moduleResolution setting because there is no such corresponding setting in TypeScript right now. Put another way, when you say you’re using --module esnext, you’re allowed to write, and we will emit, the latest and greatest ES module code constructs, but we will not do anything differently with deciding how imports resolve. You’ll likely continue using --moduleResolution node, which was designed for Node’s implementation of CJS. What does this mean for you? If you’re writing ESM for Node, you can probably make some stuff work with --module esnext and --moduleResolution node, but newer Node-specific features like package.json exports won’t work, and it will be extremely easy to shoot yourself in the foot when writing import paths. Paths will be evaluated by tsc under Node’s CJS rules, but then at runtime, Node will evaluate them under its ESM rules since you’re emitting ESM. There are significant differences between these algorithms—notably, the latter requires relative imports to use file extensions instead of dropping the .js, and index files have no special meaning, so you can’t import the index file just by naming the path to the directory.
Differences in module
The difference observable in the --module setting itself is a bit more subtle. As I mentioned before, in esnext you aren’t allowed to write import Foo = require("bar") because we assume there is no require. In nodenext, we know that a given module might be an ES module or it might be a CJS module, based on its file extension (.mts → .mjs implies ESM and .cts → .cjs implies CJS) and/or the type field in the nearest package.json file. --module nodenext enables looking at these things to make decisions about what kind of module a given file is, which controls what kind of module output we emit. If the aforementioned conditions result in a module being interpreted as CJS, the output for that file is nearly identical (maybe identical?) to what you’d get from --module commonjs. If the module is interpreted as ESM, the output is very similar to what you’d get from --module esnext, with one exception I can recall off the top of my head: you’re still allowed to write import Foo = require("bar"), and that gets compiled to:
import { createRequire as _createRequire } from "module";
const __require = _createRequire(import.meta.url);
const Foo = __require("bar");
Summary
I think the answer to your question can be summarized like this:
Node 12+ has support for CJS and ESM side-by-side, indicated by package.json type and special file extensions, so we need a module emit mode that understands that stuff. That mode can be thought of roughly as a Node-based selector between the existing commonjs and esnext modes, with a few additional little differences tailored to Node.
Node 12+ also brings major new features to how module specifiers in packages can resolve, and enforces a different and much stricter resolution algorithm specifically for ESM imports. Without a matching TypeScript resolution mode, we both fail to resolve in the face of those new features and let you write paths that won’t resolve in ESM resolution.
I am creating a Node Project with Typescript and I have set the target option to es6 in tsconfig.json
Node version 8 supports the async/await syntax but Typescript converts that to a generator function
How can I tell typescript not to convert es6 features already present in Node?
async/await is supported in ES2017, so u may need to set your target in tsconfig.json to ES2017.
P.S. You may find meseret an interesting library to work with, if you're into TypeScript, async/await and Node.
I have a Node.js project I recently converted to TypeScript from ECMAScript 6-compatible JavaScript. I am still not entirely familiar with how TypeScript and ES6 interact, especially in regards to namespaces and types.
I have a subfolder in my project called sql which, as it sounds, exports a number of functions to interact with the project's MySQL database. I would like to organize my DB model types in a Sql.Models namespace, so they can be referenced e.g. Sql.Models.User. I would like my models to be declared in one or more .d.ts files inside the sql folder, but I can't figure out how to properly organize this so that these types can be referenced elsewhere. I obviously cannot require or import a .d.ts file; that's not a valid TypeScript operation. How can I use the type Sql.Models.User declared in a .d.ts file in another ES6-compatible TypeScript module?
How can I use the type Sql.Models.User declared in a .d.ts file in another ES6-compatible TypeScript module?
The following very simple setup works.
root
sql
models.d.ts
index.ts
tsconfig.json
The model.d.ts file declares a namespace and a type. As the image demonstrates, the index.ts file can alias that namespace and/or access it directly.
The above is using TypeScript version 2.2.1.
I solved this in a less-than-pretty fashion by using "aliased internal imports" which sound strange but really aren't. I export an alias to an internal symbol, which just happens to be a symbol imported from another file.
I would have preferred something like how C# works, where I can define the namespace in two files and somehow alias one from another so that only one file needs to be referenced, but this doesn't seem possible with ECMAScript 6-compatible TypeScript.
Has anybody got a setup working in which module 1 using typescript is referencing another module 2 also with typescript and both use tsd types such as node.d.ts ?
I have no problem compiling both and using them, as long as i simply require module 2. But as soon as i use import instead, i get into duplicate identifier hell, due to the fact that source files in both modules import e.g. node.d.ts typings from obviously different paths. Classes in both projects use e.g 'streams' or 'lodash' thus both use them in typings and thus use the /// reference syntax. The tsconfig in both projects excludes typings.
Typescript has come a long way since this was asked, and it's now much easier. You can link the proper files in package.json:
{
"main": "library-commonjs.js",
"module": "library-es6-module.js",
"typings": "library-commonjs.d.ts"
}
main is used by packages using CommonJS and Node.js module resolution. module is used by packages supporting ES6 imports. And typings is followed by Typescript (currently Typescript 2.2) to resolve type definitions for the package.
After struggling with this, I spent some time creating a typescript boilerplate/starter project that demonstrates how to do it properly:
https://github.com/bitjson/typescript-starter
That project includes a lot more documentation, and several examples of how to import code from typescript projects.
EDIT: With TS 2.2 this has gotten quite a lot better. See the accepted answer.
It seems this is not really possible yet in typescript 1.8.x. But they seem to work on it via https://github.com/Microsoft/TypeScript/issues/7156.
Also the problem is supposedly mitigated by using a jsconfig.json which should be used by VScode (see https://blogs.msdn.microsoft.com/vscode/2015/07/06/visual-studio-code-es6/). Sadly i didnt get it working yet.
now that nodejs4 support classes and arrow functions, how do I tell typescript not to polyfill it?
now that nodejs4 support classes and arrow functions, how do I tell typescript not to polyfill it
You might think you can use target es6, but don't. E.g. the following in TypeScript :
function test(bar = 123){
}
Compiles to JavaScript with target es6:
function test(bar = 123) {
}
But default parameters aren't supported by node yet (reference)
Till the compatibility table of Node exceeds that of TypeScript ... be very careful! or just target es5.
Assuming you're using TypeScript now for node, you are likely specifying that your target output is ES5. Which means that it will polyfill/transpile ES6/7 features into the paradigm of ES5 in order to run in today's browsers and previous versions of node.
In order to use those features of ES6 today in node v4 you would just need to change your build process to output ES6 via the target option.
Note: this is true if you are using command line arguments or a tsconfig.json