I have a function that shold return me another function to compare two objects by a specified key, like this:
function compareTexts(text1: string, text2: string, caseSensitive = false): 0 | -1 | 1 {
const t1 = (caseSensitive ? text1 : text1.toLowerCase()).trim();
const t2 = (caseSensitive ? text2 : text2.toLowerCase()).trim();
return t1 === t2 ? 0 : t1 < t2 ? -1 : 1;
}
function compareByProp(prop: string) {
return (a: any, b: any) => compareTexts(a[prop], b[prop]);
}
(see typescript playground with example)
I'd like to get rid of the any
types, and return a function that would only accept object with the prop
key in it.
like this:
// this should be OK
console.log( compareByProp('name')({ name: 'sas', age: '2' }, { name: 'aaa', age: '5' }))
// this should err, because objects don't have the `agex` property
console.log( compareByProp('agex')({ name: 'sas', age: '2' }, { name: 'aaa', age: '5' }))
I tried withi this:
function compareByProp(prop: string) {
return (a: { [prop]: string }, b: { [prop]: string }) => compareTexts(a[prop], b[prop]);
}
But I get the following error: A computed property name in a type literal must refer to an expression whose type is a literal type or a 'unique symbol' type.(1170)
Any idea how to achieve it, or a better approach to handle it?
CodePudding user response:
You need to use a generic to describe the property:
function compareByProp<TProp extends PropertyKey>(prop: TProp) {
return (a: { [k in TProp]: string }, b: { [k in TProp]: string }) => compareTexts(a[prop], b[prop]);
}
Note that PropertyKey
is just a standard alias for string | number | symbol
which are the supported key types.