False positive in typescript:S4144

  • What language is this for? Typescript
  • Which rule? S4144
  • Why do you believe it’s a false-positive/false-negative? Because it directly contradicts documentation.
  • Are you using
    • SonarQube for IDE - which IDE/version? v5.9.1 for VSCode, not in connected mode
  • How can we reproduce the problem? Scan the text below and note the warning on the line flagged by comments.
type ServerResponseCore = {
	attr1: string;
	attr2?: number;
};

type Routes = {
	'alpha': ServerResponseCore & { alice?: number },
	'beta': ServerResponseCore & { bob?: string },
	'gamma': ServerResponseCore & { charlie?: number },
	'delta': ServerResponseCore & { david?: string },
};

async function postJson<R extends keyof Routes> (
	route: R,
	routeBody: any, //pretend this is more careful
): Promise<Routes[R]> {
	//pretend this is an HTTP request...
	return {
		attr1: 'demo',
		attr2: 42,
	};
}

const makeHTTPRequest = async <
	S extends ServerResponseCore,
>(
	post: () => Promise<S>,
	handleRouteSpecificResponse: (response: S) => void,
) => {
	const serverResponse = await post();
	console.log(serverResponse.attr1, serverResponse.attr2);
	handleRouteSpecificResponse(serverResponse);
};

const callAlpha = async (
	alphaParam1: string,
	alphaParam2: number, //...
) => {
	const route = 'alpha' as const;
	const routeBodyObj = {
		//more complex construction in reality
		alphaParam1,
		alphaParam2,
	};
	const post = () => postJson(
		route,
		routeBodyObj,
	);
	type PostResponse = Awaited<ReturnType<typeof post>>;
	const handleRouteSpecificResponse = (
		serverResponse: PostResponse,
	) => {
		console.log(serverResponse.alice);
	};
	await makeHTTPRequest(
		post,
		handleRouteSpecificResponse,
	);
};

const callBeta = async (
	betaParam1: string,
	betaParam2?: number, //...
) => {
	const route = 'beta' as const;
	const routeBodyObj = {
		betaParam1,
		betaParam2,
	};
	//Warning on next line:
	//"Update this function so that its implementation is not identical
	//to the one on line 45. [+1 location] (typescript:S4144)"
	//Yet under "Issue Details" there are two listed "Exceptions":
	//1. Functions with fewer than 3 lines are ignored.
	//2. This rule does not apply to function expressions
	//and arrow functions because they don’t have explicit names
	//and are often used in a way where refactoring is not applicable.
	//Thus per description, this rule should NOT flag a warning here.
	//Also, this function gets typed differently than the one above.
	const post = () => postJson(
		route,
		routeBodyObj,
	);
	type PostResponse = Awaited<ReturnType<typeof post>>;
	const handleRouteSpecificResponse = (
		serverResponse: PostResponse,
	) => {
		console.log(serverResponse.bob);
	};
	await makeHTTPRequest(
		post,
		handleRouteSpecificResponse,
	);
};

See also this thread for a false positive on the typing point, but the documentation makes it seem like this rule shouldn’t be flagging here under the documented exceptions.

Hi @unblocker

Sorry for the delayed reply, and thanks for the detailed report. I reproduced the issue and agree that it is a false positive in this case.

You’re right that the rule description says arrow functions are excluded. That is a documentation gap: the implementation does check arrow functions assigned directly to variables, such as post. Inline arrow callbacks are excluded. So in a sense the issue raised here is intended. But I agree reporting a single call expression because it spans several lines is not useful. We’ll update the documentation and investigate how we can improve the rule. One possibility is counting statements instead of lines, which would avoid the issue in your case.

You also pointed out that the two post functions have different inferred types. The rule currently compares their source bodies without considering types. Sometimes identical bodies with different types can be shared through a generic function so flagging duplication may still be useful, but I recognize that abstraction is not always worthwhile. We’ll investigate whether we should consider type information when checking for duplicates.

I’ve created a ticket to track the work. Unfortunately, I don’t have an ETA yet for when the improvements will land.

Best,

Lijun

Thanks for the reply. Might you be willing to share a link to the ticket so that further progress can be tracked by clicking through to there?

Also, I recognize the implementation checks arrow functions assigned directly to a variable and the documentation disagrees, but maybe a better solution is to fix the implementation instead of just updating the documentation?

Hey @unblocker, here’s the ticket, sorry, normally we drop the link but we forgot this time. You can see there the scope covered by this fix. We’re mainly fixing the spec, but changing the implementation is more of a “to be considered” point.

Thanks. I think changing the spec alone without any description of why (or without any note that it’s an arbitrary implementation decision) is likely to leave folks confused, and if there is no good reason why, creating a ticket to fix the implementation is probably a better idea.