removing duplicates in an array with new Set gives an error - javascript

I am trying to remove duplicates in an array with new Set gives an error "new Set(names).slice is not a function"
const names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
const uniq = [ ...new Set(names) ];
console.log(uniq);
Here is the code on stackblitz

I was able to fix the error by adding a tsconfig.json in the root of the project. It is a super simple config:
{
"compilerOptions": {
"target": "es6"
}
}
What is happening is that TypeScript is compiling to an es3 version of javascript which is the default if no target is configured as shown here (see --target).

When your code goes through the build phase and is translated from TypeScript to JavaScript, the second line you posted becomes:
var uniq = new Set(names).slice();
Personally I would consider that a TypeScript bug but I never use TypeScript so I can't say for sure.
edit — actually I don't think it happens unless you're targeting ES5.

Related

Property 'cause' does not exist on type 'Error' in new Vue 3 project

I created a new Vue app via npm init vue#latest with the following setup
I replaced the content of the App.vue file with
<script setup lang="ts">
const e = new Error("something failed");
console.log(e.cause);
</script>
I get the following error
Property 'cause' does not exist on type 'Error'. Do you need to change your target library? Try changing the 'lib' compiler option to 'es2022' or later.ts(2550)
Based on the docs the cause property should exist. I added "lib": ["ESNext"], to tsconfig.vitest.json, tsconfig.config.json and tsconfig.app.json ( I don't know which one needs it ). Then I get the error
Cannot find name 'console'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'dom'.ts(2584)
so I add it too and it seems to be fine now. It feels wrong to me since this already is a web project and I don't think the basic setup is lacking essential features...
So are there any better solutions for this?
I also tried to set this field inside the tsconfig.json file like so
{
"files": [],
"compilerOptions": {
"lib": ["ESNext", "DOM"],
},
"references": [
{
"path": "./tsconfig.config.json"
},
{
"path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.vitest.json"
}
]
}
but this didn't work, then cause does not exist on type Error again.
I just want to have access to the cause property of Error inside a new Vue project :)
You need to first set an cause for the error and later you can console log it.
const myError = new Error('Databse status:503')
myError.cause = 'Database failed to connect!'
console.log(myError.cause)

How do I add global types to eslint/emmet in vscode?

NOTE: This is NOT a typescript question. I'm using JavaScript, not TypeScript
ESLint/Emmet in VSCode is aware of certain global types. For example: I type
const ctx = AudioC
And vscode/eslint/emmet auto completes it to AudioContext.
And if I continue and type
const ctx = new AudioContext();
ctx.create
it clearly knows the type since it provides completions for that type, not just that it's a global
How do I add new global completions/type data? For example these types
https://www.npmjs.com/package/#webgpu/types
even if I have to convert them to some other form
As it is VSCode/ESlint/Emmet are not aware of them.
Note: I'm not asking about /* global someName */ nor am I asking about "specifying globals". Neither of those adds new types.
Also note, I'm asking how to add them at a global level. In other words, if just create a new file and type
const a = GPUBufferUsage.
It needs to complete, the same as if I had typed
const b = navigator.
I didn't have to add any special comments or annotations to the file. the types are added at a global level.
half of the solution:
VSCode uses typescript to do its type completion even when in JavaScript
See VSCode docs: https://code.visualstudio.com/docs/nodejs/working-with-javascript
To add global types you can add a jsconfig.json file. The jsconfig.json file has the same format as a tsconfig.json file except it defaults to allowJs: true. Otherwise it's the same so you can configure it the same. For the referenced package above something like this seems to work
jsconfig.json
{
"compilerOptions": {
"target": "ESNext",
"module": "esnext",
"typeRoots": [
"./node_modules/#webgpu/types"
]
},
"exclude": ["node_modules", "**/node_modules/*"]
}
and adding the types for the package above with
npm install --save-dev #webgpu/types
This doesn't help eslint. It still complains. But you can manually add them to your .eslintrc file. For this particular file I extracted them with
grep "declare var" ./node_modules/#webgpu/types/dist/index.d.ts | sed 's/declare var \(.*\):.*$/"\1",/'
If there is an more standard way to get eslint to recognize those globals please add an answer.

New error when accessing properties of top "Object is possibly 'null'." after upgrading to TS 4.4.3

I recently upgraded my project to TypeScript 4.4.3 from 3.9.9.
My project's using "strictNullChecks": true, in its tsconfig.json, and runs in the browser, not server-side on Node.
In TypeScript 4.4.3, it seems like the type declarations for top has changed to WindowProxy | null (node_modules/typescript/lib/lib.dom.d.ts)
This means that I get the following error1 wherever I try to access properties of top2: TS Playground
const topUrl = top.window.location.href; // => Object is possibly 'null'.
How can I ignore this category of errors only for when top is possibly null?3
1 I understand that this error is warning me against the scenario where my website is loaded in an iframe, and therefore can't access top due to XSS. This isn't an issue because my 'X-Frame-Options' is set to 'sameorigin' and will therefore refuse to load my website in a cross-origin iframe.
2 I access properties of top because I use iframes inside my project a lot, where it loads sub-pages on the same domain.
3 I could use the following fixes to get around this Object is possibly 'null'., but I'd prefer not to, as my project is quite large and this fix would be tedious with minimal improvement.
let topUrl = top?.window.location.href || '';
let topUrl = '';
if (top) {
topUrl = top.window.location.href;
}
I could also ignore these errors on every line with // #ts-ignore, but there's a lot of references to top and I don't want to clutter the project (also, other TypeScript errors on the same line would be ignored).
// #ts-ignore
const topUrl = top.window.location.href;
I found a solution which would possibly fit your needs. And there are 2 versions of the solution you can take into consideration.
Both of these versions work by overriding the built-in lib-dom with a npm package #types/web which is also provided by Microsoft.
Beta but systematic one - Using the latest official 'lib override' from typescript#4.5.0-beta
Follow steps below and things are gonna work as you expect without any other code modifications:
Upgrade to TypeScript 4.5.0:
npm i -D typescript#4.5.0-beta
or install globally
npm i -g typescript#4.5.0-beta
Install the #types/web#0.0.1 type package which has top: Window type
npm i -D #typescript/lib-dom#npm:#types/web#0.0.1
I have made some simple tests on this solution and managed to get behaviour you want.
The only shortcoming of this solution is that typescript#4.5 is still beta currently. But It worth your consideration since its final release will be just on next month.
TypeScript 4.5 Iteration Plan
Stable one - typescript 4.4.3 and switch the built-in dom lib.
install #types/web
npm i -D #types/web#0.0.1
notice that the install command is different from the above one.
Update your tsconfig.json. There are two cases to consider depending on if you have lib defined in your tsconfig.json or not.
Without "lib" - You will need to add "lib": []. The value you want to add inside your lib should correlate to your "target". For example if you had "target": "es2017", then you would add "lib": ["es2017"]
With "lib" - You should remove "dom".
The drawback of this second version of solution is, it cannot prevent your dependencies in node_modules from pulling in the TypeScript DOM library.
Please bear in mind that despite #types/web is up to version 0.0.40, only version 0.0.1 of #types/web has top typed top: Window instead of top: WindowProxy | null which is what you need.
The problem
You decided to upgrade your compiler version, and, as mentioned in a comment, major software version changes almost always come with breaking API changes.
The correct way to solve your issue (prevent compiler errors) is to modify your source code to satisfy the compiler. You said that modifying your source code in this way would be a chore, and asked about modifying the compiler configuration instead such that you can avoid modifying your source code.
It is not possible to override the types in lib.dom.d.ts in new type declarations. TypeScript will emit additional errors if you attempt to do this, even if you disable type-checking of your new declaration file, resulting in an incompatible merging of your new declarations. Your only option is to exclude the built-in DOM library and provide your own modified version of it.
Here is an overview of how to do that:
Starting TSConfig
You haven't provided your tsconfig.json file, so here's an example to use as a base, with the assumption that your source is organized in your repo's src/ directory:
Note: "strict": true implies "strictNullChecks": true
{
"compilerOptions": {
"isolatedModules": true,
"lib": [
"esnext",
"dom",
"dom.iterable"
],
"module": "esnext",
"outDir": "dist",
"strict": true,
"target": "esnext"
},
"include": [
"./src/**/*"
]
}
Creating the modified lib.dom.d.ts library
First download the lib.dom.d.ts file from the tag that matches your TypeScript version (4.4.3): https://github.com/microsoft/TypeScript/blob/v4.4.3/lib/lib.dom.d.ts
Move the file to src/types/lib.dom.d.ts in your project
Remove the triple-slash reference on line 18 by deleting the entire line. (This will allow you to continue using other built-in libraries.)
Modify line 17286 from this:
readonly top: WindowProxy | null;
to this:
readonly top: WindowProxy;
Modify line 18350 from this:
declare var top: WindowProxy | null;
to this:
declare var top: WindowProxy;
Save the file
Modifying your TSConfig
Now that you have a replacement library for the DOM types in your program, you need to tell the compiler to use it that way. Here's what you need to change:
{
"compilerOptions": {
// ...
"lib": [
"esnext",
"dom", // Delete this from the array
"dom.iterable"
],
// ...
// Add this array property
"typeRoots": [
"./node_modules/#types",
"./src/types"
]
},
// ...
}
So the modified tsconfig.json now looks like this:
{
"compilerOptions": {
"isolatedModules": true,
"lib": [
"esnext",
"dom.iterable"
],
"module": "esnext",
"outDir": "dist",
"strict": true,
"target": "esnext",
"typeRoots": [
"./node_modules/#types",
"./src/types"
]
},
"include": [
"./src/**/*"
]
}
Conclusion
That's it. Now you should be able to compile your program and reference window.top or just the global top as a non-nullable value without a compiler error.
You'll need to repeat this process every time you upgrade TypeScript. Is this strategy more sustainable than modifying your source code? That's up to you.
I preface this answer with a strong warning that I would not do this to my project and encourage anyone in this position to fix the errors the proper way using null coalescing or not null assertion. EG:
window.top!.scrollTo()
top!.scrollTo()
window.top?.scrollTo()
top?.scrollTo()
// etc..
Even though theres 1500 I think using some regular expression you could easily target a large portion of those errors and fix with ease. With that said heres some other options:
I havent done this in a production project and might result in some other strange errors, its largely untested by myself outside of quick testing
The summary of this solution is you could clone the lib.dom.ts file and make the modifications by hand.
Copy ./node_modules/typescript/lib/lib.dom.d.ts to somewhere in your project, say ./lib.dom.modified-4.4.3.d.ts
Make the modifications to remove the null type from window.top and top types
// old
// readonly top: WindowProxy | null;
// new
readonly top: WindowProxy;
...
// old
// declare var top: WindowProxy | null;
// new
declare var top: WindowProxy;
Update your tsconfig.json to remove dom as one of the libraries and add it to the list of types
{
"compilerOptions": {
"lib": [
"ES6"
],
"strictNullChecks": true,
"module": "commonjs",
"target": "ES6",
"types": [
"./lib.dom.modified-4.4.3"
]
},
"include": [
"src/**/*"
]
}
Now you have a custom dom library with the top property not nullable
Alternatively you could make a patch for lib-dom using git and apply it post install. Details about how to do that are outlined in several solutions of this question How to overwrite incorrect TypeScript type definition installed via #types/package
You can initialize a VCS if you have not already done so. Then
look at the place of your error
see what you would need to replace it to
use whatever tools you use to replace all occurrences of the source text to the target text
if there are still errors, repeat
Once you have replaced all occurrences of issues this way, you will need to review your changes. You will find the changes via the VCS. If you use git, then the command is
git diff
See all the changes and whichever looks even a little bit suspect, investigate and see whether the automatic change was correct. If not, perform whatever you need to ensure that your code is correct.
Test everything. You would do well if you would create a separate versioning branch for this work which would be tested for a long time before it's being released to production.
instead that you shoud use !, that typescript ignores the fact that the value could be null which in your case it is not
const topUrl = top!.window.location.href;
if your ES-LINT complains on that you can set the in config file like that
module.exports = {
...
rules: {
...
'#typescript-eslint/no-non-null-assertion': 'off'
},
...
}
I access properties of top because I use iframes inside my project a lot, where it loads sub-pages on the same domain.
top is potentially null...
This isn't an issue because my 'X-Frame-Options' is set to 'sameorigin' and will therefore refuse to load my website in a cross-origin iframe.
But you're saying that's impossible, in which case...
function getTop(): NonNullable<typeof top> {
if (!top) throw new Error('global var top is null');
return top;
}
...then replace any occurrence of top.example with getTop().example so as to centralize all potential 'null' errors.
While this isn't the most simple solution, it should be the safest.
In your question, you state:
I could use the following fixes to get around this Object is possibly 'null'., but I'd prefer not to, as my project is quite large and this fix would be tedious with minimal improvement.
let topUrl = top?.window.location.href || '';
I can appreciate the tedious nature of this task, but if you're insistent on using TypeScript, I must also be insistent that you employ this solution. It is necessary in TypeScript.
One way I would solve this problem would be to use my code editor/IDE program to search/replace all text references in my project. I use Visual Studio Code which allows me to Search and Replace specific text in my source files. It allows for Regex searching, including and excluding particular files. I'm certain that a great majority of code editors/IDEs have similar functionality.

Linter error in Deno project tsconfig.json, and cascading into project files - but code runs successfully?

I need to use the ES2019 flatMap() method on an array in a Deno project, so I have created a tsconfig.json file as below:
{
"compilerOptions": {
"target": "es5",
"lib": [
"es2019"
]
}
}
This gives what appear to be 6 of the same linter errors, specifically Cannot find type definition file for 'cacheable-request' in the tsconfig.json file. Have I created this file incorrectly or somehow caused conflict with the Deno structure?
In a project module where I am attempting to use flatMap() I am seeing the error
Property 'flatMap' does not exist on type 'number[][]'. Do you need to change your target library? Try changing the `lib` compiler option to 'es2019' or later.
This doesn't make much sense since I have set my lib to es2019 in my tsonfig - unless I've created it wrong and it's thus not being picked up... then again the code works, so I'm assuming that it has correctly compiled to es2019.
Am I missing some aspect of creating a tsconfig file for a Deno project that allows use of es2019?
I believe there's no need normally to include a tsconfig.json in order to use ES2019 features in Deno. I was able to use flatMap without problems in Deno 1.9.0, for example:
// mod.ts
const map = [1,2,3,[1,2,3],[1,2]].flatMap((_value, _index, _array) => {
return 1;
});
console.log(map);
deno run mod.ts
>> [ 1, 1, 1, 1, 1 ]
I couldn't find if this was unsupported or bugged in previous versions but try upgrading Deno and omitting tsconfig.json to fix this.

Can't use let in webstorm

I am studying typescript and I'm trying to create a simple let and it won't work because it says I need to use ECMA6 or higher. This is is the error message I'm getting in the typescript compiler:
Error:(11, 5) TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher.
And this is the code:
class website{
url:string;
facebookLikes:number;
}
let google = new website();
google.url = "google.com";
google.facebookLikes = 23124;
I searched online and I found an answer that says to go to settings and langauges and frameworks and go to javascript and change it to EcmaScript6. I done this but I still get the same error.
If anyone can shed some light on this I would really appreciate it. Thanks.
You need to use the ES6 target just as the error suggests.
I don't know how you compile your typescript files, if it's using the builtin compiler or a file watcher, but in any case the compiler options have the target property which should be ES6 if you want to use let (and other es6 features).
If for example you are using tsconfig.json then it should look like this:
{
"compilerOptions": {
"target": "ES6",
...
}
}

Categories