VSCode auto import - Not working for Rxjs operators - visual-studio-code

I have a project where VS Code won't suggest imports when using rxjs operators.
myObservable.pipe(
take(1),
filter(result => result),
switchMap((result) => myOtherObserbable),
finalize(() => this.isLoading = false)
)
In this scenario, take, filter, switchMap and finalize won't provide any suggestion in the contextual menu:
I have to manually write:
import { take, filter, switchMap, finalize } from "rxjs/operators";
And then it works.
What could cause that and where should I look for?

Found out the issue in tsconfig file:
"paths": {
"#app/*": ["app/*"],
"#env/*": ["environments/*"],
"#angular/*": ["../node_modules/#angular/*"],
"rxjs/*": ["../node_modules/rxjs/*"], // => Commenting this makes the imports work
"#custom/library": ["../../../path/to/custom/library/src"]
}
I'm using a custom library and had to add paths for the project to know where to look, but apparently it brokes the auto import

Related

Open Web Components Testing / Lit - component not being rendered?

I'm trying to test my Lit components with #open-wc/testing. Lit has an example repo here, with this test:
https://github.com/lit/lit-element-starter-ts/blob/main/src/test/my-element_test.ts#L44
When I try to render my element like they do in their example, I get this error:
jtests/components/coding-editor.test.ts:
🚧 Browser logs:
HTMLElement: <coding-editor></coding-editor>
❌ renders
TypeError: Cannot read properties of null (reading 'querySelector')
at o.<anonymous> (jtests/components/coding-editor.test.ts:16:30)
My component works in the browser and uses the name "coding-editor". It's as if this test renderer has no idea that I'm using a custom component though. I don't know why shadowRoot is null in my case.
My code is roughly this:
import { CodingEditor } from '../../app/javascript/components/coding-editor';
import {expect, fixture} from '#open-wc/testing';
import {html} from 'lit/static-html.js';
it('renders', async () => {
const el = await fixture(html`
<coding-editor></coding-editor>
`) as CodingEditor;
console.log(el);
const text = el.shadowRoot!.querySelector('.table-constrainer');
// expect(text).to.not.be.null
});
How can I get my test to render this properly, with the shadowRoot populated?
This is likely due to TypeScript removing the CodingEditor import that's only used as a type so the side effect of defining the custom element is not happening.
You can either set the TS compiler option importsNotUsedAsValues to preserve (See https://www.typescriptlang.org/tsconfig/#importsNotUsedAsValues) or add another import line for the side-effect like
import '../../app/javascript/components/coding-editor';
Additional explanation here too: https://github.com/Microsoft/TypeScript/wiki/FAQ#why-are-imports-being-elided-in-my-emit
As a side-note, in the starter example you linked to, the imported class is used in assert.instanceOf as a value so it does not get elided by TypeScript.

Flutter : A member named 'read' is defined in extensions 'ReadContext' and 'BuildContextX' and neither is more spesific

I have a button in my application that return :
onPressed: () {
return context
.read(FavoriteIds.provider.notifier)
.toggle(doa.id.toString());
},
In this case, i used a riverpod provider. But when i want to import a flutter_bloc package, the read keyword will be error with this message
A member named 'read' is defined in extensions 'ReadContext' and 'BuildContextX' and neither is more specific. Try using an extension override to specify the extension you want to to be chosen.
Please help me solve this problem. thank you :)
Here the problem is read() is defined in both ReadContext & BuildContextX extensions. So the compiler is not getting which extension to use.
To solve the error, use : ReadContext(context).read if you wanna access bloc or BuildContextX(context).read() as per your need.
This means you are importing 2 extensions that both supply the same method read. Consider this example:
extension Ext1 on String {
void foo() => print("from extension 1");
}
extension Ext2 on String {
void foo() => print("from extension 2");
}
void main() {
String s = "hello";
s.foo();
}
What should this code print? There isn't an obvious answer, and to avoid accidental programming errors, Dart prohibits this.
You could try "go-to definition" (ctrl/cmd click in most IDEs) on the read method to navigate to one of the files that it is defined in, and then delete the corresponding import statement.
However, it might be quicker to just delete all the import statements in that file and add them back with autocomplete

Rescript Capitalised Component

From the Rescript Documentation, it is suggested spread can be used to enable passing a pre-existing list to a component. I am confused what exactly MyComponentis in Rescript as I cannot find a way to initialise a component, which can be done with a function in vanilla React.
<MyComponent>...myChild</MyComponent>
where myChild = list{child1,child2}
After several attempts, the followings do not work:
#JSX div(~children=myChild) , because Rescript asks for wrapping it in a list as in list{myChild}
#JSX div(~children=list{myChild}), which gives a type error
Initialising a module named MyComponent, and do <MyComponent> ...myChild </MyComponent>, but this gives the error The value make can't be found in MyComponent
Initialising a function with a capitalisation escape: let \"MyComponent" = () => ..., but this gives the error The module or file MyComponent can't be found.
What I would love is an example of the initialization of the component MyComponent which can be used as a capitalised tag like <MyComponent>...myChild</MyComponent>. Thank you in advance.
module MyComponent = {
#react.component
let make = (~children: list<React.element>) => {
<div> {Belt.List.toArray(children)->React.array} </div>
}
}
From Rescript Forum.

Subscribe is deprecated: Use an observer instead of an error callback

When I run the linter it says:
subscribe is deprecated: Use an observer instead of an error callback
Code from this angular app:
this.userService.updateUser(data).pipe(
tap(() => {bla bla bla})
).subscribe(
this.handleUpdateResponse.bind(this),
this.handleError.bind(this)
);
Don't know exactly what should I use and how...
Thanks!
subscribe isn't deprecated, only the variant you're using is deprecated. In the future, subscribe will only take one argument: either the next handler (a function) or an observer object.
So in your case you should use:
.subscribe({
next: this.handleUpdateResponse.bind(this),
error: this.handleError.bind(this)
});
See these GitHub issues:
https://github.com/ReactiveX/rxjs/pull/4202
https://github.com/ReactiveX/rxjs/issues/4159
Maybe interesting to note that the observer Object can also (still) contain the complete() method and other, additional properties. Example:
.subscribe({
complete: () => { ... }, // completeHandler
error: () => { ... }, // errorHandler
next: () => { ... }, // nextHandler
someOtherProperty: 42
});
This way it is much easier to omit certain methods. With the old signature it was necessary to supply undefined and stick to the order of arguments. Now it's much clearer when for instance only supplying a next and complete handler.
For me, it was just the typescript version my VSCode was pointing to.
Got help from this GitHub comment.
I believe this is a typescript issue. Something in the newest versions of typescript is causing this warning to display in vs code. I was able to get it to go away by click the version of typescript in the bottom right corner of vs code and then choosing the select typescript version option. I set it to the node_modules version we have installed in our angular project which in our case happens to be 4.0.7. This caused the warnings to go away.
Find the details at official website
https://rxjs.dev/deprecations/subscribe-arguments
Notice the {} braces in second subscribe code below.
import { of } from 'rxjs';
// recommended
of([1,2,3]).subscribe((v) => console.info(v));
// also recommended
of([1,2,3]).subscribe({
next: (v) => console.log(v),
error: (e) => console.error(e),
complete: () => console.info('complete')
})
You can get this error if you have an object typed as Observable<T> | Observable<T2> - as opposed to Observable<T|T2>.
For example:
const obs = (new Date().getTime() % 2 == 0) ? of(123) : of('ABC');
The compiler does not make obs of type Observable<number | string>.
It may surprise you that the following will give you the error Use an observer instead of a complete callback and Expected 2-3 arguments, but got 1.
obs.subscribe(value => {
});
It's because it can be one of two different types and the compiler isn't smart enough to reconcile them.
You need to change your code to return Observable<number | string> instead of Observable<number> | Observable<string>. The subtleties of this will vary depending upon what you're doing.
I migrated my Angular project from TSLint to ESLint and it is now not showing the warning anymore!
I followed these steps. (End of each step I also recommend to commit the changes)
Add eslint:
ng add #angular-eslint/schematics
Convert tslint to eslint:
ng g #angular-eslint/schematics:convert-tslint-to-eslint
Remove tslint and codelyzer: npm uninstall -S tslint codelyzer
If you like to auto fix many of the Lint issues
ng lint --fix (It will also list the not fixed issues)
In VSCode uninstall the TSLint plugin, install ESLint plugin and Reload the VSCode.
Make sure it updated the package and package-lock files. Also the node_modules in your project.
If you have the tsconfig.json files under sub directory - you need to add/update the projects-root-directory/.vscode/settings.json with the sub directory where the tsconfig files are!
{
"eslint.workingDirectories": [
"sub-directory-where-tsconfig-files-are"
]
}
Information at VS Code official Page: Migrate from TSLint to ESLint (Thanks for pointing this out in the comment!)
Angular migrate from TSLint to ESLint Reference
I was getting the warning because I was passing this to subscribe:
myObs.subscribe(() => someFunction());
Since it returns a single value, it was incompatible with subscribe's function signature.
Switching to this made the warning go away (returns null/void);
myObs.subscribe(() => {
someFunction();
});
You should replace tslint with eslint.
As TSLint is being deprecated it does not support the #deprecated syntax of RXJS. ESLint is the correct linter to use, to do subscribe linting correctly.
The new Way of using RxJS is quit simple:
previous versions:
this.activatedRoute.queryParams.subscribe(queryParams => {
console.log("queryParams, queryParams)
}, error => {
})
New Version:
this.activatedRoute.queryParams.subscribe(
{
next: (queryParams) => {
console.log('queryParams', queryParams);
},
error: (err: any) => { },
complete: () => { }
}
);
Subscribe isn't deprecated.
So you should use:
import { of } from 'rxjs';
.subscribe({
next: (n) => console.log(n),
error: (e) => console.error(e),
complete: () => console.info('complete')
})

Using TypeScript with Dojo - import/export issues

In the company I work for we are using Dojo framework and lately I have started pushing to use it with TypeScript.
I took a look around and found this great article on how this topic, you can find it here:
https://gregwiechec.com/2016/01/creating-dojo-widget-in-typescript/
The last 2 lines in this solution are:
var exp = _declare("alloy.editors.StringListTs", [_Widget, _TemplatedMixin, _WidgetsInTemplateMixin, _CssStateMixin, _ValueRequiredMixin], new StringList());
export = exp;
I followed the same pattern and it works great, except for 2 issues that I cant seem to have a good solid solution:
1. If you look at the solution, when calling dojo declare method, the class created needs to be instantiated (this is because dojo looks at properties and not prototype).
2. The more problematic issue, is the fact that I am exporting out the dojo declared object, and not the class it self. This is problematic when you try to import the class (typescript import), and even if I declare the variable exp as the class type, I get an error saying that there is no constructor to what i am trying to import.
I faced your same problem, and for me has been a transpiler issue.
TL;DR if you import something using the import * as WidgetName from '<path>' syntax and don't use WidgetName in the js (like you would do for a widget in a template), the transpiler won't import it. Use import '<path>' instead.
Long answer: It's my first time with TypeScript and, similarly you, I'm converting a dojo project to TypeScript. Hoping to help more people, I'll put few steps which helped me to import modules correctly.
Step 0 dojoConfig packages
Defining you own package on dojoConfig won't work, modules must be referenced using relative path.
To be clear, with this example:
dojoConfig = {
...
packages : [ { name : "myproject", location : "js/myproject" },
{ name : "dojo", location : dojoBase+"dojo" },
{ name : "dijit", location : dojoBase+"dijit" },
{ name : "dojox", location : dojoBase+"dojox" } ]
};
It's not possible to have widget importing each other with import * as WidgetName from 'myproject/WidgetName' approach, but rather you have to import * as WidgetName from './WidgetName' (notice the '.' vs 'myproject').
Step 1: importing dojo declaration (not mandatory, as far as I noticed)
I'm relying on node, I pulled dojo-typing using npm install dojo-typings --save-dev. In the files property I specified [ "src/js/**/*.ts", "src/js/**/*.js", "node_modules/dojo-typings/dojo/1.11/index.d.ts", "node_modules/dojo-typings/dojo/1.11/modules.d.ts", "node_modules/dojo-typings/dijit/1.11/index.d.ts", "node_modules/dojo-typings/dijit/1.11/modules.d.ts" ].
Step 2: using the correct options on the transpiler:
{
"target": "es5",
"allowJs": true,
"module": "amd",
"moduleResolution": "classic",
"noImplicitUseStrict" : true
},
noImplicitUseStrict solved the error dojo/parser::parse() error TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them. allowJs allowed me to mix TypeScript and native dojo together.
Step 3: returning using export
This is an example of a very minimal module which doesn't require/import anything, but only exports a log method (file would be 'toast.ts'):
const log = function(message) {
window['dojo'].publish("mainTopic",
[{
message: "<span style='font-size: 12px;'>" + message +"</span>",
type: 'info',
duration: 3000
}]
);
}
export { log }
For completeness, in pure Dojo you would have written something like (file would be 'toast.js'):
define([ ],
function(){
var log = function(message) {
dojo.publish("mainTopic",
[{
message: "<span style='font-size: 12px;'>" + message +"</span>",
type: 'info',
duration: 3000
}]
);
};
return { log : log };
});
Step 4: rewrite your widget and import it correctly
I use a Main widget which takes all the body, here the content of Main.ts:
/// <amd-dependency path="dojo/text!./Main.html" name="template" />
declare var template: string;
import * as _Widget from 'dijit/_Widget';
import * as _TemplatedMixin from 'dijit/_TemplatedMixin';
import * as _WidgetsInTemplateMixin from 'dijit/_WidgetsInTemplateMixin';
import * as dojoDeclare from 'dojo/_base/declare';
import './MyVanillaJavascriptWidget';
import './MyModule';
import 'dojox/widget/Toaster';
import toast = require('./utility/toast');
export default dojoDeclare("mm.Main", [ _Widget, _TemplatedMixin, _WidgetsInTemplateMixin ], {
templateString : template,
});
There are different types of imports:
the first is the one I struggled the most, for the template
import * as ... is a sequence of dojo objects I use in the class
import '<path>' is used for widget I declared in the template using data-dojo-type
import name = require('<path>') is another way to require modules
For completeness, this would be the original Main.js file:
define([ "dijit/_Widget", "dijit/_TemplatedMixin", "dijit/_WidgetsInTemplateMixin",
"dojo/_base/declare", "dojo/text!./Main.html",
"dojox/widget/Toaster", "./MyVanillaJavascriptWidget", "./MyModule"
],
function( _Widget, _TemplatedMixin, _WidgetsInTemplateMixin, declare, mainTemplate, toast) {
return declare("mm.Main", [ _Widget, _TemplatedMixin, _WidgetsInTemplateMixin ], {
templateString : mainTemplate,
});
});
Conclusion: The missing constructor most probably comes from the way you import a module, checking the transpiled code helped me to understand where the issue was. To succeed with the import, a bit of accuracy is needed here and there (all the steps above should give an overview).
I'm still in the process of converting my project (other issues may come out), but I hope this helps also other poor souls trying to use TypeScript with Dojo!