我有一个认知复杂度为 24 的函数,但我们只允许它最大为 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;
};
}
高认知复杂性的一个原因是依偎的 ifs,而且很多都在 for..of 循环下。所以即使我将代码提取到一个单独的函数中,认知复杂度也会太高。如何降低其复杂性?
答案 0 :(得分:1)
这可能更适合代码审查,但我会开始重构
分解文字类型
- 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>
删除所有类型断言
- return parseNumber(parameterValue) as Parsed<T> | null;
+ return parseNumber(parameterValue);
使用有意义的变量名(名字太长和太短一样糟糕)
- const parameterValueChildren = parseStruct(parameterValue);
+ const children = parseStruct(val);
一旦准备好,您就可以开始重构您的逻辑,这将是更简单的“由内而外”:不是在解析器中检查结构类型,而是在外部进行并为每种类型返回一个特定的解析器:
export function parameterValueParser<T extends Structure>(struct: T): Parser<T> {
if (isParameterValueNumber(struct)) {
return parseNumber;
}
if (isParameterValueStruct(struct)) {
return structValueParser(struct);
}
etc....
}