'How to efficiently refactor if...if statement in typescript
as an exercise, I am trying to find the most efficient way to refactor this if...if statement.
This is the original code:
interface Validatable {
value: string | number;
required?: boolean;
minLength?: number;
maxLength?: number;
min?: number;
max?: number;
}
function validate(validatableInput: Validatable) {
let isValid = true;
if (validatableInput.required) {
isValid = isValid && validatableInput.value.toString().trim().length !== 0;
}
if (
validatableInput.minLength != null &&
typeof validatableInput.value === 'string'
) {
isValid =
isValid && validatableInput.value.length >= validatableInput.minLength;
}
if (
validatableInput.maxLength != null &&
typeof validatableInput.value === 'string'
) {
isValid =
isValid && validatableInput.value.length <= validatableInput.maxLength;
}
if (
validatableInput.min != null &&
typeof validatableInput.value === 'number'
) {
isValid = isValid && validatableInput.value >= validatableInput.min;
}
if (
validatableInput.max != null &&
typeof validatableInput.value === 'number'
) {
isValid = isValid && validatableInput.value <= validatableInput.max;
}
return isValid;
}
and this is what I achieved so far:
function validate(validatableInput: Validatable) {
const { required, minLength, maxLength, min, max } = validatableInput; // This methos extracts the properties from the object
const validatableInputValue = validatableInput.value;
let isValid = true;
if (required) {
isValid = isValid && validatableInputValue.toString().trim().length !== 0;
}
if (minLength != null && typeof validatableInputValue === "string") {
isValid = isValid && validatableInputValue.length >= minLength;
}
if (maxLength != null && typeof validatableInputValue === "string") {
isValid = isValid && validatableInputValue.length <= maxLength;
}
if (min != null && typeof validatableInputValue === "number") {
isValid = isValid && validatableInputValue >= min;
}
if (max != null && typeof validatableInputValue === "number") {
isValid = isValid && validatableInputValue <= max;
}
return isValid;
}
Is there anything else I could do? Like use a switch statement instead, or something else? Thank you!
Solution 1:[1]
All of the conditions follow a pattern: if a particular prerequisite is fulfilled, then validate the input value against something. You can exploit this by creating an array of such conditions: each item can have a prerequisite (eg required) and a test (eg value.toString().trim().length !== 0). Then iterate over the array with something like .every to check that each truthy prerequisite has its corresponding condition fulfilled.
function validate(validatableInput: Validatable) {
const { required, minLength, maxLength, min, max, value } = validatableInput;
const isStr = typeof value === "string";
const isNum = typeof value === "number";
const conditions = [
[required, value.toString().trim().length !== 0],
[minLength != null && isStr, value.length >= minLength],
[maxLength != null && isStr, value.length <= maxLength],
[min != null && isNum, value >= min],
[max != null && isNum, value <= max],
];
return conditions.every(([prereq, result]) => result || !prereq);
}
Solution 2:[2]
As another approach that keeps the existing structure:
function validate(validatableInput: Validatable) {
const { value, required, minLength, maxLength, min, max } = validatableInput;
if (required && value.toString().trim().length === 0) {
return false;
}
if (typeof value !== "string" || typeof value !== "number") {
return true
}
if (typeof value === "string") {
if (minLength && value.length < minLength) {
return false;
}
if (maxLength && value.length > maxLength) {
return false;
}
}
if (min && value < min) {
return false;
}
if (max && value > max) {
return false;
}
return true;
}
A few things of note:
- Some people have problems with early returns; I don't--it's immediately clear while reading what happens without having to continue reading the function.
- It's not as elegant as the
everyoption, but it allows for easier modification, logging, etc. because it's very explicit and blocked out. - Since
Validatableis a type I'm not sure why this functionality wants to be pulled out of it, particularly since decisions are being made based on type information of aValidatableproperty.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | CertainPerformance |
| Solution 2 | Dave Newton |
