Info
Language: Typescript
Rule: S3699
Reported on: SonarQube 10.2.1 (build 78527)
Information
When using Typescript’s declare
statement, the declared function is always considered as not returning anything.
This triggers false positives for typescript:S3699 when the return value of such function is used.
Analysis
It seems the root cause of the issue is in the no-use-of-empty-return-value.ts implementation in the eslint-plugin-sonarjs project.
There is a functionsWithReturnValue
variable that is used to store all functions that have a return value.
Functions are added to it when parsing ReturnStatement
, ArrowFunctionExpression
and ':function'
nodes. However, it probably should include support for TSDeclareFunction
nodes.
An untested fix proposal is available at the bottom of the post.
Repro Snippet
declare function setTimeout(fn: () => void, t: number, ...args: unknown[]): NodeJSTimeout | number;
export function async(fn: () => void): void {
const t: NodeJSTimeout | number = setTimeout(fn, 0); // *** S3699 issue reported on this line ***
if (isNodeJSTimeout(t)) { t.unref(); }
}
interface NodeJSTimeout {
readonly unref: () => NodeJSTimeout;
}
function isNodeJSTimeout(v: unknown): v is NodeJSTimeout {
return (typeof v === "object") && (v !== null) && (typeof (v as Readonly<Record<string | number | symbol, unknown>>)["unref"] === "function");
Fix Proposal (Untested)
const rule: TSESLint.RuleModule<string, string[]> = {
// ... existing code ...
create(context) {
// ... existing code ...
return {
// ... existing code ...
// *** START OF NEW CODE **
TSDeclareFunction(node: TSESTree.Node) {
const declareFunction = node as TSESTree.TSDeclareFunction;
if (declareFunction.returnType?.typeAnnotation.type !== 'TSVoidKeyword') {
functionsWithReturnValue.add(declareFunction);
}
},
// *** END OF NEW CODE
};
},
};