Skip to content

Commit f442dbd

Browse files
feat(no-misused-observables): assignments
1 parent ad628d2 commit f442dbd

File tree

2 files changed

+74
-2
lines changed

2 files changed

+74
-2
lines changed

src/rules/no-misused-observables.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export const noMisusedObservablesRule = ruleCreator({
4949
},
5050
name: 'no-misused-observables',
5151
create: (context) => {
52-
const { program, esTreeNodeToTSNodeMap } = ESLintUtils.getParserServices(context);
52+
const { program, esTreeNodeToTSNodeMap, getTypeAtLocation } = ESLintUtils.getParserServices(context);
5353
const checker = program.getTypeChecker();
5454
const { couldBeObservable, couldReturnObservable } = getTypeServices(context);
5555
const [config = {}] = context.options;
@@ -64,7 +64,7 @@ export const noMisusedObservablesRule = ruleCreator({
6464
TSInterfaceDeclaration: checkClassLikeOrInterfaceNode,
6565
Property: checkProperty,
6666
ReturnStatement: checkReturnStatement,
67-
// AssignmentExpression: checkAssignment,
67+
AssignmentExpression: checkAssignment,
6868
// VariableDeclarator: checkVariableDeclarator,
6969
};
7070

@@ -223,6 +223,20 @@ export const noMisusedObservablesRule = ruleCreator({
223223
});
224224
}
225225

226+
function checkAssignment(node: es.AssignmentExpression): void {
227+
const varType = getTypeAtLocation(node.left);
228+
if (!isVoidReturningFunctionType(varType)) {
229+
return;
230+
}
231+
232+
if (couldReturnObservable(node.right)) {
233+
context.report({
234+
messageId: 'forbiddenVoidReturnVariable',
235+
node: node.right,
236+
});
237+
}
238+
}
239+
226240
return {
227241
...(checksVoidReturn ? voidReturnChecks : {}),
228242
...(checksSpreads ? spreadChecks : {}),

tests/rules/no-misused-observables.test.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,30 @@ ruleTester({ types: true }).run('no-misused-observables', noMisusedObservablesRu
205205
}
206206
`,
207207
// #endregion valid; void return return value
208+
// #region valid; void return variable
209+
{
210+
code: stripIndent`
211+
// void return variable; explicitly allowed
212+
import { Observable, of } from "rxjs";
213+
214+
let foo: () => void;
215+
foo = (): Observable<number> => of(42);
216+
`,
217+
options: [{ checksVoidReturn: false }],
218+
},
219+
stripIndent`
220+
// void return variable; not void
221+
import { Observable, of } from "rxjs";
222+
223+
let foo: () => Observable<number>;
224+
foo = () => of(42);
225+
`,
226+
stripIndent`
227+
// void return variable; unrelated
228+
let foo: () => void;
229+
foo = (): number => 42;
230+
`,
231+
// #endregion valid; void return variable
208232
// #region valid; spread
209233
{
210234
code: stripIndent`
@@ -721,6 +745,40 @@ ruleTester({ types: true }).run('no-misused-observables', noMisusedObservablesRu
721745
`,
722746
),
723747
// #endregion invalid; void return return value
748+
// #region invalid; void return variable
749+
fromFixture(
750+
stripIndent`
751+
// void return variable; reassign
752+
import { of } from "rxjs";
753+
754+
let foo: () => void;
755+
foo = () => of(42);
756+
~~~~~~~~~~~~ [forbiddenVoidReturnVariable]
757+
`,
758+
),
759+
fromFixture(
760+
stripIndent`
761+
// void return variable; nested
762+
import { of } from "rxjs";
763+
764+
const foo: {
765+
bar?: () => void;
766+
} = {};
767+
foo.bar = () => of(42);
768+
~~~~~~~~~~~~ [forbiddenVoidReturnVariable]
769+
`,
770+
),
771+
fromFixture(
772+
stripIndent`
773+
// void return variable; Record
774+
import { of } from "rxjs";
775+
776+
const foo: Record<string, () => void> = {};
777+
foo.bar = () => of(42);
778+
~~~~~~~~~~~~ [forbiddenVoidReturnVariable]
779+
`,
780+
),
781+
// #endregion invalid; void return variable
724782
// #region invalid; spread
725783
fromFixture(
726784
stripIndent`

0 commit comments

Comments
 (0)