[Typescript]False Positive for typescript:S3699 when using declare function


Language: Typescript
Rule: S3699
Reported on: SonarQube 10.2.1 (build 78527)


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.


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') {
      // *** END OF NEW CODE
1 Like

Hello @fpascutti,

Thank you for your valuable feedback, and a warm welcome to the Sonar community!

You’re absolutely correct in highlighting that the rule is triggering false positives on TypeScript ambient functions. I’ve created this ticket to address this issue promptly.

Additionally, I really appreciate your effort in reviewing the rule implementation and suggesting a fix accordingly. We will take your fix proposal into account.