Tslint complaints "must be filtered with an if statement" when using a switch
Let's say I have the following method:
getErrorMessage(state: any, thingName?: string) {
const thing: string = state.path || thingName;
const messages: string[] = [];
if (state.errors) {
for (const errorName in state.errors) {
switch (errorName) {
case 'required':
messages.push(`You must enter a ${thing}`);
break;
case 'minlength':
messages.push(`A ${thing} must be at least ${state.errors['minlength'].requiredLength}characters`);
break;
case 'pattern':
messages.push(`The ${thing} contains illegal characters`);
break;
case 'validateCardNumberWithAlgo':
messages.push(`Card doesnt pass algo`);
break;
}
}
}
return messages;
}
when i run
ng lint
I am getting the following error:
for (... in ...) statements should be filtered with an if statement
Taking a look at a similar question , I don't think this answer will apply to my situation. After the switch statement is in the if-else-if ladder category.
tslint should treat a switch statement as a form of an if statement, but it is not !!
source to share
I was curious, so I checked the TSlint source code for this rule. It has a function called isFiltered
, which apparently only checks ts.SyntaxKind.IfStatement
, not on ts.SyntaxKind.SwitchStatement
.
function isFiltered({statements}: ts.Block): boolean {
switch (statements.length) {
case 0: return true;
case 1: return statements[0].kind === ts.SyntaxKind.IfStatement;
default:
return statements[0].kind === ts.SyntaxKind.IfStatement && nodeIsContinue((statements[0] as ts.IfStatement).thenStatement);
}
}
So if you don't want to convert your object to an array, you need to use the fix from the link you provided. Either Object.keys
or the operator if
:
for (const errorName in state.errors) {
if (state.errors.hasOwnProperty(errorName)) {
switch (errorName) {
Interestingly, you can have any operator if
and the error will go away. There is no check to see if you are calling hasOwnProperty
.
source to share
This rule is intended to prevent access to properties defined in an object's prototype when used for .. c .
However, you can refactor your code to simply not use it, and make it easier to maintain and develop.
An example would be the following:
interface ErrorMessageFactory {
(thing: string, state?): string
}
type Errors = 'required' | 'minlength' | 'pattern' | 'validateCardNumberWithAlgo'
let errorFactory: {[e in Errors]: ErrorMessageFactory} = {
required: (thing) => `You must enter a ${thing}`,
minlength: (thing, state) => `A ${thing} must be at least ${state.errors['minlength'].requiredLength}characters`,
pattern: (thing) => `The ${thing} contains illegal characters`,
validateCardNumberWithAlgo: (thing) => `Card doesnt pass algo`
}
function getErrorMessage(state: any, thingName?: string) {
if (state.errors) {
return state.errors.map((error) => errorFactory[error](thingName, state));
}
return [];
}
You can see a working snippet on the playground here .
source to share