Reputation: 359
I have this function that has a cognitive complexity of 24, but we only allow it to be maximum 15.
export function parameterValueParser<T extends Structure>(
structure: T
): (parameterValue: Value) => Parsed<T> | null {
return (parameterValue: Value): Parsed<T> | null => {
if (isParameterValueNumber(structure)) {
return parseNumber(parameterValue) as Parsed<T> | null;
}
if (isParameterValueStruct(structure)) {
const parameterValueChildren = parseStruct(parameterValue);
if (parameterValueChildren == null) {
return null;
}
const result = {} as { [_: string]: Parsed<Structure> };
for (const key in structure) {
if (structure.hasOwnProperty(key)) {
const child = parameterValueChildren[key];
if (child == null) {
return null;
}
const parsedChild = parameterValueParser(structure[key])(child);
if (parsedChild == null) {
return null;
}
result[key] = parsedChild;
}
}
return result as Parsed<T>;
}
return null;
};
}
One reason for the high cognitive complexity is the nestled ifs, and many under a for..of loop. So even if I would extract the code to a separate function, the cognitive complexity will be too high. How to reduce its complexity?
Upvotes: 0
Views: 487
Reputation: 214959
This might be better suited for codereview, but I'd start refactoring by
factoring out literal types
- export function parameterValueParser<T extends Structure>(structure: T): (parameterValue: Value) => Parsed<T> | null
+ type Parser<T> = (val: Value) => Parsed<T> | null;
+ export function parameterValueParser<T extends Structure>(structure: T): Parser<T>
removing all type assertions
- return parseNumber(parameterValue) as Parsed<T> | null;
+ return parseNumber(parameterValue);
using meaningful variable names (too long names are just as bad as too short)
- const parameterValueChildren = parseStruct(parameterValue);
+ const children = parseStruct(val);
Once this is ready, you can start refactoring your logic, which will be simpler "inside-out": instead of checking the structure type in the parser, do it outside and return a specific parser for each type:
export function parameterValueParser<T extends Structure>(struct: T): Parser<T> {
if (isParameterValueNumber(struct)) {
return parseNumber;
}
if (isParameterValueStruct(struct)) {
return structValueParser(struct);
}
etc....
}
Upvotes: 1