Skip to content

Commit

Permalink
feat(no-return-void): add option to allow for checking implicit retur…
Browse files Browse the repository at this point in the history
…n types
  • Loading branch information
RebeccaStevens committed Aug 1, 2021
1 parent ba8fe86 commit 6fb1604
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 12 deletions.
8 changes: 7 additions & 1 deletion docs/rules/no-return-void.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ This rule accepts an options object of the following type:
{
allowNull: boolean;
allowUndefined: boolean;
ignoreImplicit: boolean;
}
```

Expand All @@ -47,7 +48,8 @@ The default options:
```ts
{
allowNull: true,
allowUndefined: true
allowUndefined: true,
ignoreImplicit: true,
}
```

Expand All @@ -58,3 +60,7 @@ If true allow returning null.
### allowUndefined

If true allow returning undefined.

### ignoreImplicit

If true ignore functions that don't explicitly specify a return type.
51 changes: 42 additions & 9 deletions src/rules/no-return-void.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@ import { JSONSchema4 } from "json-schema";

import {
createRule,
getTypeOfNode,
RuleContext,
RuleMetaData,
RuleResult,
} from "../util/rule";
import {
isFunctionLike,
isNullType,
isTSNullKeyword,
isTSUndefinedKeyword,
isTSVoidKeyword,
isUndefinedType,
isVoidType,
} from "../util/typeguard";

// The name of this rule.
Expand All @@ -20,6 +25,7 @@ export const name = "no-return-void" as const;
type Options = {
readonly allowNull: boolean;
readonly allowUndefined: boolean;
readonly ignoreImplicit: boolean;
};

// The schema for the rule options.
Expand All @@ -33,6 +39,9 @@ const schema: JSONSchema4 = [
allowUndefined: {
type: "boolean",
},
ignoreImplicit: {
type: "boolean",
},
},
additionalProperties: false,
},
Expand All @@ -42,6 +51,7 @@ const schema: JSONSchema4 = [
const defaultOptions: Options = {
allowNull: true,
allowUndefined: true,
ignoreImplicit: true,
};

// The possible error messages.
Expand Down Expand Up @@ -73,17 +83,40 @@ function checkFunction(
context: RuleContext<keyof typeof errorMessages, Options>,
options: Options
): RuleResult<keyof typeof errorMessages, Options> {
if (node.returnType === undefined) {
if (!options.ignoreImplicit && isFunctionLike(node)) {
const functionType = getTypeOfNode(node, context);
const returnType = functionType
?.getCallSignatures()?.[0]
?.getReturnType();

if (
returnType !== undefined &&
(isVoidType(returnType) ||
(!options.allowNull && isNullType(returnType)) ||
(!options.allowUndefined && isUndefinedType(returnType)))
) {
return {
context,
descriptors: [{ node, messageId: "generic" }],
};
}
}
} else if (
isTSVoidKeyword(node.returnType.typeAnnotation) ||
(!options.allowNull && isTSNullKeyword(node.returnType.typeAnnotation)) ||
(!options.allowUndefined &&
isTSUndefinedKeyword(node.returnType.typeAnnotation))
) {
return {
context,
descriptors: [{ node: node.returnType, messageId: "generic" }],
};
}

return {
context,
descriptors:
node.returnType !== undefined &&
(isTSVoidKeyword(node.returnType.typeAnnotation) ||
(!options.allowNull &&
isTSNullKeyword(node.returnType.typeAnnotation)) ||
(!options.allowUndefined &&
isTSUndefinedKeyword(node.returnType.typeAnnotation)))
? [{ node: node.returnType, messageId: "generic" }]
: [],
descriptors: [],
};
}

Expand Down
12 changes: 12 additions & 0 deletions src/util/typeguard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -403,3 +403,15 @@ export function isObjectConstructorType(
export function isNeverType(type: Type): boolean {
return ts !== undefined && type.flags === ts.TypeFlags.Never;
}

export function isVoidType(type: Type): boolean {
return ts !== undefined && type.flags === ts.TypeFlags.Void;
}

export function isNullType(type: Type): boolean {
return ts !== undefined && type.flags === ts.TypeFlags.Null;
}

export function isUndefinedType(type: Type): boolean {
return ts !== undefined && type.flags === ts.TypeFlags.Undefined;
}
28 changes: 26 additions & 2 deletions tests/rules/no-return-void.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ const valid: ReadonlyArray<ValidTestCase> = [
function foo(bar) {
console.log(bar);
}`,
optionsSet: [[], [{ allowNull: false }], [{ allowUndefined: false }]],
optionsSet: [
[{ ignoreImplicit: true }],
[{ ignoreImplicit: true, allowNull: false }],
[{ ignoreImplicit: true, allowUndefined: false }],
],
},
// Allow null.
{
Expand Down Expand Up @@ -116,7 +120,7 @@ const invalid: ReadonlyArray<InvalidTestCase> = [
function foo(bar: number): (baz: number) => void {
return baz => { console.log(bar, baz); }
}`,
optionsSet: [[]],
optionsSet: [[{ ignoreImplicit: true }]],
errors: [
{
messageId: "generic",
Expand All @@ -126,6 +130,26 @@ const invalid: ReadonlyArray<InvalidTestCase> = [
},
],
},
// Disallow implicit return type.
{
code: dedent`
function foo(bar) {
console.log(bar);
}`,
optionsSet: [
[{ ignoreImplicit: false }],
[{ ignoreImplicit: false, allowNull: false }],
[{ ignoreImplicit: false, allowUndefined: false }],
],
errors: [
{
messageId: "generic",
type: "FunctionDeclaration",
line: 1,
column: 1,
},
],
},
];

describeTsOnly("TypeScript", () => {
Expand Down

0 comments on commit 6fb1604

Please sign in to comment.