@@ -84,6 +84,10 @@ ruleTester({ types: true }).run('no-misused-observables', noMisusedObservablesRu
8484 const Baz = class extends Foo {
8585 foo(): Observable<number> { return of(42); }
8686 }
87+
88+ interface Qux extends Foo {
89+ foo(): Observable<number>;
90+ }
8791 ` ,
8892 options : [ { checksVoidReturn : false } ] ,
8993 } ,
@@ -375,6 +379,190 @@ ruleTester({ types: true }).run('no-misused-observables', noMisusedObservablesRu
375379 }
376380 ` ,
377381 ) ,
382+ fromFixture (
383+ stripIndent `
384+ // void return inherited method; interface; extends class
385+ import { Observable } from "rxjs";
386+
387+ class Foo {
388+ foo(): void {}
389+ }
390+
391+ interface Bar extends Foo {
392+ foo(): Observable<number>;
393+ ~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Foo" }]
394+ }
395+ ` ,
396+ ) ,
397+ fromFixture (
398+ stripIndent `
399+ // void return inherited method; interface; extends abstract
400+ import { Observable } from "rxjs";
401+
402+ abstract class Foo {
403+ abstract foo(): void;
404+ }
405+
406+ interface Bar extends Foo {
407+ foo(): Observable<number>;
408+ ~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Foo" }]
409+ }
410+ ` ,
411+ ) ,
412+ fromFixture (
413+ stripIndent `
414+ // void return inherited method; interface; extends interface
415+ import { Observable } from "rxjs";
416+
417+ interface Foo {
418+ foo(): void;
419+ }
420+
421+ interface Bar extends Foo {
422+ foo(): Observable<number>;
423+ ~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Foo" }]
424+ }
425+ ` ,
426+ ) ,
427+ fromFixture (
428+ stripIndent `
429+ // void return inherited method; interface; extends conditional type
430+ import { Observable } from "rxjs";
431+
432+ type Foo<IsRx extends boolean = true> = IsRx extends true
433+ ? { foo(): Observable<void> }
434+ : { foo(): void };
435+
436+ interface Bar extends Foo<false> {
437+ foo(): Observable<void>;
438+ ~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "{ foo(): void; }" }]
439+ }
440+ ` ,
441+ ) ,
442+ fromFixture (
443+ stripIndent `
444+ // void return inherited method; interface; extends multiple
445+ import { Observable } from "rxjs";
446+
447+ interface Foo {
448+ foo(): void;
449+ }
450+
451+ interface Bar {
452+ foo(): void;
453+ }
454+
455+ interface Baz extends Foo, Bar {
456+ foo(): Observable<void>;
457+ ~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Foo" }]
458+ ~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Bar" }]
459+ }
460+ ` ,
461+ ) ,
462+ fromFixture (
463+ stripIndent `
464+ // void return inherited method; interface; extends multiple classes
465+ import { Observable } from "rxjs";
466+
467+ class Foo {
468+ foo(): void {}
469+ }
470+
471+ class Bar {
472+ foo(): void {}
473+ }
474+
475+ interface Baz extends Foo, Bar {
476+ foo(): Observable<void>;
477+ ~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Foo" }]
478+ ~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Bar" }]
479+ }
480+ ` ,
481+ ) ,
482+ fromFixture (
483+ stripIndent `
484+ // void return inherited method; interface; extends typeof class
485+ import { Observable } from "rxjs";
486+
487+ const Foo = class {
488+ foo(): void {}
489+ }
490+
491+ type Bar = typeof Foo;
492+
493+ interface Baz extends Bar {
494+ foo(): Observable<void>;
495+ ~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "typeof Foo" }]
496+ }
497+ ` ,
498+ ) ,
499+ fromFixture (
500+ stripIndent `
501+ // void return inherited method; interface; extends function, index, constructor
502+ import { Observable } from "rxjs";
503+
504+ interface Foo {
505+ (): void;
506+ (arg: string): void;
507+ new (): void;
508+ [key: string]: () => void;
509+ [key: number]: () => void;
510+ myMethod(): void;
511+ }
512+
513+ interface Bar extends Foo {
514+ (): Observable<void>;
515+ (arg: string): Observable<void>;
516+ new (): Observable<void>;
517+ [key: string]: () => Observable<void>;
518+ [key: number]: () => Observable<void>;
519+ myMethod(): Observable<void>;
520+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Foo" }]
521+ }
522+ ` ,
523+ ) ,
524+ fromFixture (
525+ stripIndent `
526+ // void return inherited method; interface; extends multiple function, index, constructor
527+ import { Observable } from "rxjs";
528+
529+ interface Foo {
530+ (): void;
531+ (arg: string): void;
532+ }
533+
534+ interface Bar {
535+ [key: string]: () => void;
536+ [key: number]: () => void;
537+ }
538+
539+ interface Baz {
540+ new (): void;
541+ new (arg: string): void;
542+ }
543+
544+ interface Qux {
545+ doSyncThing(): void;
546+ doOtherSyncThing(): void;
547+ syncMethodProperty: () => void;
548+ }
549+
550+ interface Quux extends Foo, Bar, Baz, Qux {
551+ (): void;
552+ (arg: string): Observable<void>;
553+ new (): void;
554+ new (arg: string): void;
555+ [key: string]: () => Observable<void>;
556+ [key: number]: () => void;
557+ doSyncThing(): Observable<void>;
558+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Qux" }]
559+ doRxThing(): Observable<void>;
560+ syncMethodProperty: () => Observable<void>;
561+ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [forbiddenVoidReturnInheritedMethod { "heritageTypeName": "Qux" }]
562+ // TODO(#66): couldReturnType doesn't work for properties.
563+ }
564+ ` ,
565+ ) ,
378566 // #endregion invalid; void return inherited method
379567 // #region invalid; spread
380568 fromFixture (
0 commit comments