I want to sort an array of objects by either a string or a number. If it is a string, I want to call .toLowerCase()
on it first. I'm making that distinction using typeof
in the condition of a ternary statement.
interface ObjectProps {
sortFoo: string,
sortBar: number
}
const sortBy: "sortFoo" | "sortBar" = getSortKey();
const sortList = (...args: ObjectProps[]): number => {
const compare: (string | number)[] = args.map(
(arg: ObjectProps): string | number => typeof arg[sortBy] === 'string' ? arg[sortBy].toLowerCase() : arg[sortBy]
);
return compare[0] < compare[1] ? -1 : 1;
}
const objects: ObjectProps[] = getArrayOfObjects().sort(sortList);
This code will run just fine, but TS flags .toLowerCase()
with this error:
TS2339: Property toLowerCase does not exist on type string | number
Property toLowerCase does not exist on type number
How do I tell the TS engine that if typeof myVar === 'string'
evaluates as false, then myVar
is not a string?
I tried replacing the ternary with a full if
clause, as in this tutorial (scroll down to the section titled "Unknown"), but TS still showed the same error. Not sure what else to try.
Looks like Typescript only performs that type narrowing on a variable, not necessarily a property that you're accessing. So you just need to store the property in a variable first, something like this:
const sortList = (...args: ObjectProps[]): number => {
const compare: (string | number)[] = args.map(
(arg: ObjectProps): string | number => {
const sortVal = arg[sortBy];
return typeof sortVal === 'string' ? sortVal.toLowerCase() : sortVal;
}
);
return compare[0] < compare[1] ? -1 : 1;
}