I'm learning TS and I'm creating a sort function that sort my array of objects using a params as key using bracket notation. The code above works well, but if I want to extend in the future, i should add every conditions. I want to validate by the type of the value of the key that I want to use.
I try things like the code above and it works to validate but TS keep throwing errors that property/methods inside the IF are not valid because it takes all existing types from every key of my interface and not only the ones that really can go through the condition
if(typeof arr[prop] === "string")
if(arr[prop] instanceof String)
if(arr[prop].constructor.name === "String")
This is the code
interface Person{
name: string,
age: number,
isAlive: boolean}
const myArr = [
{name: 'Tomás',
age: 24,
isAlive: true},
{name: 'Kate',
age: 12,
isAlive: true},
{name: 'Brad',
age: 54,
isAlive: false},
{name: 'Angelica',
age: 64,
isAlive: true},
]
function myFn(
arr: Person[],
orderBy: keyof Person): Person[] {
if(orderBy === 'name'){
return arr.sort((a,b) => a[orderBy].localeCompare(b[orderBy]));
}
else if (orderBy === "age") {
return arr.sort((a, b) => a[orderBy] - b[orderBy]);
}
else if (orderBy === "isAlive") {
return arr.sort(value => value[orderBy] ? -1 : 1)
}
else {
return [];
}
}
const byAlive = myFn(myArr, "isAlive");
console.log(byAlive)
const byAge = myFn(myArr, "age");
console.log(byName)
const byName = myFn(myArr, "name");
console.log(byName)
Thanks in advance and sorry for my English, I'm not native :) If I'm not clear with something or you can't understand me, please let me know so I try to write it in a better way.
CodePudding user response:
First of all, Typescript has difficulty narrowing a type through a dynamic property access like:
if (typeof person[prop] === 'string') person[prop].toUpperCase() // error
You can make this easier for Typescript by assigning the result of person[prop]
to a variable, and then using that. For example:
const value = person[prop]
if (typeof value === 'string') value.toUpperCase() // works
So then, make just one array.sort
call where you save the property value from a
and b
to separate variables, and then test the types to find the proper comparison.
For example:
function myFn(
arr: Person[],
orderBy: keyof Person
): Person[] {
return arr.sort((aPerson, bPerson) => {
const a = aPerson[orderBy]
const b = bPerson[orderBy]
if (typeof a === 'string' && typeof b === 'string') {
return a.localeCompare(b)
}
if (typeof a === 'number' && typeof b === 'number') {
return a - b
}
if (typeof a === 'boolean' && typeof b === 'boolean') {
return a ? 1 : -1
}
throw Error('unsupported value type')
})
}