I'm new with Typescript and I have a problem with using a variable to choose the property of an object.
I have a function that filters an array on a property passed as a parameter. The function receives 3 parameters: an array of objects, the characters sought and the property that will be filtered. here is the function.
type Data = {
[key: string]: string | number;
};
function filtreTexte(arr: Data[], searchCar: string, field: string): Data[] {
return arr.filter((el) => {
if (el[field] === "string") {
return el[field].toLowerCase().indexOf(searchCar.toLowerCase()) !== -1;
}
})
}
The problem on the .toLowerCase() which tells me that the method does not work on a number|string type even though I am testing if it is indeed a string. If I change the el[field] to el.name, the error is no longer mentioned. How should I do it ? Thank you in advance for your help.
CodePudding user response:
Your check for the type needs to look like this: if (typeof el[field] === "string")
rather than if (el[field] === "string")
- the latter case will only be true if the value of el[field]
is exactly 'string'.
CodePudding user response:
You need to wrap the el[field] into an variable declaration, this offers more specific info about the variable type since was declard before, el[field] is dynamic value wich can be string or number, so this will thrown an error.
const element = el[field];
if (typeof element === 'string') {
return element.toLowerCase().indexOf(searchCar.toLowerCase()) !== -1;
}
Also, it works with el.name because is a specific property, the same way as the above example.
Hope it helps.
CodePudding user response:
What @Dakeyras said is correct. You should add the typeof
operator.
But the narrowing will still not work. Even though we checked if the type of el[field]
is string
, the compiler will inconveniently forget this fact when we try to use it next. Generally the compiler would not try to narrow the type in this scenario where el
has an index signature and field
is just some string. A lot of things could break if that would happen. For example, field
could have changed between the check and later usage. For a further discussion on all the different limitations of TypeScript's Control Flow Analysis, see this.
To make this work, assign el[field]
to an extra variable val
, perform the narrowing on val
and then use val
later. Also don't forget to add another return statement to make the "Not all code paths return a value." error disappear.
function filtreTexte(arr: Data[], searchCar: string, field: string): Data[] {
return arr.filter((el) => {
const val = el[field]
if (typeof val === "string") {
return val.toLowerCase().indexOf(searchCar.toLowerCase()) !== -1;
}
return false
});
}