Home > Enterprise >  type a generic comparator function with typescript
type a generic comparator function with typescript

Time:09-21

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.

  • Related