tsc don't transpile .at() function - node.js

When transpiling TS to JS compatible with NodeJS v14, using the following config:
{
"compilerOptions": {
"lib": ["es2020"],
"rootDir": "src",
"outDir": "build",
"module": "commonjs",
"moduleResolution": "node",
"target": "es2020",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"skipLibCheck": true,
}
}
It was expected that the usage of at(index) would be converted to a compatible JS code, but in fact, when I ran the built code it generates (...).at is not a function error.
[1,2,3].at(-1)
The transpiled code still makes use of .at(index), but I was expecting it would get transpiled to something compatible with the target set on tsconfig.js
target: "es2020"
What am I not getting correctly here?

The TypeScript compiler considers this method as syntactically correct, which is why it does not downlevel it. You can read it better explained in this great answer to a similar question.
However I did not mark your question as duplicate because there is one information that's missing: why don't you have a compiler error?!
If you go to the TS playground, you can see that there is an immediate error if you try to write:
[1, 2, 3].at(0);
Property 'at' does not exist on type 'number[]'. Do you need to change your target library? Try changing the 'lib' compiler option to 'es2022' or later.
My guess is that you don't have an error because you are using a wrong version of the package #types/node (most probably the latest one). Indeed, as indicated on node.green, Array.prototype.at() is supported since NodeJS 16.8.0. As such, the latest typings for NodeJS reflect that fact and they provide a signature for that method, which gets automatically included by TSC.
In conclusion, install the same version of NodeJS types as your NodeJS runtime and you should get the TSC error:
npm install #types/node#14

Related

Typescript compilerOptions module & moduleResolution

I find many tsconfig.json samples always have compilerOptions like this
"module": "commonjs",
"moduleResolution": "node"
I feel setting them both as such seems unnecessary because if moduleResolution is node the module is definitely commonjs. The module is commonjs, moduleResolution is definitely node too (I can't think of any other case)
Isn't that is the case?
--- update ---
Now I realize it is not always the case because nodejs has fully support ES Modules, so I can use "module": "ES2020" & "moduleResolution": "node" (for nodejs 14+) but of course if I set "module":"commonjs" I don't need to set "moduleResolution": "node"
Further refer to What TypeScript configuration produces output closest to Node.js 14 capabilities?
Being explicit about configuration can prevent undesired behavior if a default value changes in the future in a breaking way.
The documentation explains the relationships between these configuration properties. I'll inline the default behaviors below:
moduleResolution:
Default:
Classic if module is AMD, UMD, System or ES6/ES2015,
Matches if module is node12 or nodenext,
Node otherwise.
Allowed:
classic
node
module:
Default:
CommonJS if target is ES3 or ES5,
ES6/ES2015 otherwise.
Allowed:
none
commonjs
amd
umd
system
es6/es2015
es2020
es2022
esnext
node12
nodenext
target:
Default:
ES3
Allowed:
es3
es5
es6/es2015
es2016
es2017
es2018
es2019
es2020
es2021
esnext

Typescript: Import type from package without dependencies from other types in the same package

I have a NPM package written in Typescript (let's call it libd) that offers some classes and types. They are exported in a index.ts file like this:
export { ClassA } from "./ClassA";
export { TypeB } from "./TypeB";
The ClassA is using an external dependency (let's call it depc) that is set to peerDependencies in the package.json. The TypeB is just a type without any external dependencies.
In the package.json the main field is set to dist/index.js (where it is transpiled to) and types are set to dist/index.d.ts.
The tsconfig.json of the libd package looks like this:
{
"compilerOptions": {
"target": "ES2019",
"module": "commonjs",
"declaration": true,
"outDir": "dist",
"rootDir": "src",
"inlineSources": true,
"inlineSourceMap": true
}
}
Now I im consume the TypeB in another library (let's call it libe) without importing ClassA and without having the depc dependency installed. The libd library is installed via NPM and the type is imported like this:
import { TypeB } from "libd";
The tsconfig.json of libe is similar to the one from libd.
Transpiling this gives me the error TS2307: Cannot find module 'depc'.
Now I understand, if I would use ClassA I must install depc since it imports it. But I'm only using TypeB that does not require any dependencies and sometimes types come with the original package.
I could fix this problem by installing #types/depc and Typescript would be happy. Code should work at runtime, since no actual usage of depc comes from libe. But I would rather not install useless packages.
Setting "skipLibCheck": true in the tsconfig.json of libe would also fix the tsc error but I am not sure what negative impacts this would have.
So my question is: Why does typescript check a class from dependency that I am not importing? Is it, because I have bundled all exports of the libd package in an index.ts file and all imports of those are going through this index file?
Can I resolve this without separating TypeB and ClassA into different packages? That would make them very small packages and for ~80% of the time they would be installed both.
Is it, because I have bundled all exports of the libd package in an index.ts file […]?
Yes.
TypeScript compiler sees that you are using the file libd/dist/index.{js|d.ts} and starts evaluating its exports. While doing so, it finds out that ClassA is using depc, and goes for evaluating depc, – but it is nowhere to be found (since it isn't installed). That's a definitive error.
TypeScript compiler doesn't check whether you are using ClassA or not, it is not its job to perform tree shaking.
Using "skipLibCheck": true is actually a good way of solving this problem, since its description states explicitly:
Rather than doing a full check of all d.ts files, TypeScript will type check the code you specifically refer to in your app’s source code.
… which is ultimately what you want, right?

#Types/Sequelize Error TS1086: An accessor cannot be declared in ambient context

I have a project that shows this error when I run 'tsc':
../modules/node_modules/sequelize/types/lib/transaction.d.ts:33:14 - error TS1086: An accessor cannot be declared in an ambient context.
33 static get LOCK(): LOCK;
~~~~
../modules/node_modules/sequelize/types/lib/transaction.d.ts:40:7 - error TS1086: An accessor cannot be declared in an ambient context.
40 get LOCK(): LOCK;
~~~~
My versions are:
"#types/sequelize": "^4.28.6"
"sequelize": "^5.8.10"
"sequelize-typescript": "1.0.0-beta.4"
The project works fine with nodemon but fails when I try to compile the typescript. Anyone knows this error?
Thanks.
I have Angular 8. it is working with typescript version of 3.4.5. so solve this issue do below steps.
step 1) go to the tsconfig.json file
step 2) add skipLibCheck: true in "compilerOptions" object. It works for me.
"compilerOptions": {
"module": "commonjs",
"moduleResolution": "node",
"strict": true,
"target": "es5",
"declaration": true,
"declarationDir": "dist-debug/",
"skipLibCheck": true, /// Needs to be true to fix wrong alias types being used
},
you need to use typescript 3.7.
from typescript 3.7 release notes:
To detect the issue around accessors, TypeScript 3.7 will now emit get/set accessors in .d.ts files so that in TypeScript can check for overridden accessors.
so presumably sequelize was compiled with typescript 3.7 and emits definition files that previous versions don't understand. So you'll need to upgrade to typescript 3.7 or use an earlier version of sequelize.
Setting "skipLibCheck": true worked for me.

How to force tsc to ignore node_modules folder?

I'm using tsc build tasks. Unfortunately I'm always getting the same errors from the node modules folder
Executing task: .\node_modules\.bin\tsc.cmd --watch -p .\tsconfig.json <
node_modules/#types/node/index.d.ts(6208,55): error TS2304: Cannot find name 'Map'.
node_modules/#types/node/index.d.ts(6215,55): error TS2304: Cannot find name 'Set'.
node_modules/#types/node/index.d.ts(6219,64): error TS2304: Cannot find name 'Symbol'.
node_modules/#types/node/index.d.ts(6225,59): error TS2304: Cannot find name 'WeakMap'.
node_modules/#types/node/index.d.ts(6226,59): error TS2304: Cannot find name 'WeakSet'.
10:13:18 - Compilation complete. Watching for file changes.
I already added the directory to the ignore at tsconfig.json
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"sourceMap": true,
"strict": false,
"noImplicitAny": false,
"strictPropertyInitialization": false,
"esModuleInterop": true,
},
"include": [
"src/*"
],
"exclude": [
"node_modules",
"./node_modules",
"./node_modules/*",
"./node_modules/#types/node/index.d.ts",
]
}
What I'm doing wrong? What should I do in order to ignore those errors?
I'm using VsCode and tsc Version 2.9.2
Quickfix is to skip the check
{
"compilerOptions": {
"skipLibCheck": true
},
}
Add an empty "types" option in "compilerOptions":
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"sourceMap": true,
"strict": false,
"noImplicitAny": false,
"strictPropertyInitialization": false,
"esModuleInterop": true,
"types": []
},
"include": [
"src/*"
],
"exclude": [
"node_modules",
"./node_modules",
"./node_modules/*",
"./node_modules/#types/node/index.d.ts",
]
}
From https://www.typescriptlang.org/docs/handbook/tsconfig-json.html
#types, typeRoots and types
By default all visible “#types” packages are included in your
compilation. Packages in node_modules/#types of any enclosing folder
are considered visible; specifically, that means packages within
./node_modules/#types/, ../node_modules/#types/,
../../node_modules/#types/, and so on.
...
Specify "types": [] to disable automatic inclusion of #types packages.
Keep in mind that automatic inclusion is only important if you’re
using files with global declarations (as opposed to files declared as
modules). If you use an import "foo" statement, for instance,
TypeScript may still look through node_modules & node_modules/#types
folders to find the foo package
You can do this right on the command line
tsc --skipLibCheck
I met this issue with typescript#3.2.1 and fixed by upgrading it to 3.7.3.
Notice with typescript#3.2.1, the skipLibCheck does not take effect. When I upgraded TypeScript the skipLibCheck: true works.
set "skipLibCheck": true inside tsconfig.json
I had a similar issue in a monorepo using yarn workspaces.
Turned out my app was using a different TypeScript version to the root workspace and bringing those in sync fixed the issue.
You can verify this in your own repo by running yarn list typescript or npm ls typescript.
If you have multiple versions of TypeScript then upgrade your projects with the lower version so that all have the highest version currently in use in your repo, e.g. yarn add -D typescript#4.5.5 (or whatever version you need)
This is random but none of the solutions here worked. I had an error occuring in a node_module and what fixed it was this:
Changing:
target: "esnext"
To any specific version, e.g.:
target: "es2020"
In case it helps some other poor traveller 🤷‍♂️
If you find yourself here and none of the other answers is solving the problem, check to make sure that you haven't set maxNodeModuleJsDepth.
If you have allowJs enabled this option lets TypeScript attempt to infer types from modules in node_modules, and skipLibCheck doesn't have any effect on that, because it's reading javascript files and not type declarations.
The default setting for maxNodeModuleJsDepth is 0, and in the vast majority of cases that's what you want (and you should prefer using #types packages instead of turning this on).
if you are here and none of the following has worked for you:
❌ Updgrade/downgrading typescript version
(NOTE: When you run the tsc command, the globally installed typescript version is used as the compiler. So even if you have the latest typescript version in your package.json, you will have to upgrade typescript globally. With npm thats npm install typescript#latest -g )
❌ Adding/Editing tsconfig options: target, types, include, exclude, allowJs, skipLibCheck
❌ npm update
❌ Deleting node_modules && npm i
❌ Deleting package-lock (don't do that btw) && npm i
I want to leave this link from the typescript config docs here for you:
What does this("types") affect?
With this knowledge, this solved the issue for me:
See what module is causing the error in the log when you run tsc. (For me it was node_modules/mongoose/types/*, so mongoose was the culprit.)
Convert all your ES6 imports of this module to commonjs's require(). (In my case import mongoose from 'mongoose' --> const mongoose = require('mongoose') )
I hope this solves your issue
Upgrade your typescript & ts-node:
"typescript": "4.9.4"
"ts-node": "10.9.1"
and use the flag --skipLibCheck when you build or put it in the compilerOtions on the tsconfig.json file ("skipLibCheck": true)...

How do I use TypeScript 1.6 with Visual Studio Code to get generators support?

I've been targeting ES6 for a while in Visual Studio Code, but when I try to switch to TypeScript, it throws errors such as:
Generators are only available when targeting ECMAScript 6
But my tsconfig.json does have the ES6 target:
{
"compilerOptions": {
"target": "ES6",
"module": "amd",
"sourceMap": true
}
}
So I tried npm install -g typescript#1.6.0-beta but it looks like VSCode doesn't care.
Generators are not currently supported.
How can I get TypeScript and generators to work properly together in VS Code?
Update
Changing typescript.tsdk to the 1.6 binary seems to fix IntelliSense errors, but this tasks.json still prints out error TS1220: Generators are only available when targeting ECMAScript 6 or higher.:
"version": "0.1.0",
"command": "/usr/local/lib/node_modules/typescript/bin/tsc",
"showOutput": "silent",
"windows": {"command": "tsc.exe"},
"isShellCommand": true,
"args": ["app.ts"],
"problemMatcher": "$tsc"
However, /usr/local/lib/node_modules/typescript/bin/tsc --target ES6 app.ts used manually in the terminal does work.
I know now!
1. IntelliSense
You can use the typescript.tsdk setting to point VSCode to TypeScript binaries. Upgrade your TypeScript to 1.6 and set the location properly.
You can do it either in your user/workspace settings, or per project in the .vscode/settings.json file. OS X example:
"typescript.tsdk": "/usr/local/lib/node_modules/typescript/lib"
2. Compiler
You also need to make sure your .vscode/tasks.json points to the new binary and makes the compiler operate in Explicit project mode, i.e. use tsconfig.json instead of taking a list of files to compile as an argument.
{
"version": "0.1.0",
"command": "/usr/local/lib/node_modules/typescript/bin/tsc",
"showOutput": "silent",
"windows": {"command": "tsc.exe"},
"isShellCommand": true,
"args": [], //do not pass any files to the compiler. This way it will use tsconfig.json where you can set target: "ES6"
"problemMatcher": "$tsc"
}
And finally tsconfig.json (in the project's root directory):
{
"compilerOptions": {
"target": "ES6", //The key, of course.
"module": "amd",
"sourceMap": true
},
"exclude": [
"node_modules",
".vscode"
]
}
Restart the editor afterwards!
You can change your user settings in VS Code and set "typescript.tsdk" to a custom location .
If you install the nightly (npm install -g typescript#next), you can point to that version of TypeScript's lib folder.
More
Reasons and setup instructions for using ts latest are covered here : https://basarat.gitbooks.io/typescript/content/docs/getting-started.html#typescript-version

Resources