【问题标题】:type a generic comparator function with typescript使用打字稿键入通用比较器函数
【发布时间】:2022-09-30 13:01:01
【问题描述】:

我有一个函数应该返回另一个函数来通过指定的键比较两个对象,如下所示:

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]);
}

(参见 typescript playground 示例)

我想摆脱any 类型,并返回一个只接受带有prop 键的对象的函数。

像这样:

// 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\' })) 

我试过这个:

function compareByProp(prop: string) {
    return (a: { [prop]: string }, b: { [prop]: string }) => compareTexts(a[prop], b[prop]);
}

但我收到以下错误: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)

知道如何实现它,或者更好的方法来处理它吗?

  • this 对你有用吗?我们只是使用泛型来“存储”传递的内容,然后使用它为ab 创建类型。
  • 太好了,请将其发布为答案,以便我接受

标签: typescript


【解决方案1】:

您需要使用泛型来描述该属性:

function compareByProp<TProp extends PropertyKey>(prop: TProp) {
    return (a: { [k in TProp]: string }, b: { [k in TProp]: string }) => compareTexts(a[prop], b[prop]);
}

请注意,PropertyKey 只是 string | number | symbol 的标准别名,这是受支持的密钥类型。

【讨论】:

    【解决方案2】:

    只是想分享我自己的解决方案

    第一次尝试:

    function comparator_bad<T, K extends keyof T>(key: K) {
        return (a: T, b: T) => a[key] === b[key] ? 0 : (a[key] > b[key] ? 1 : -1)
    }
    

    这不会捕获 a 或 b 中缺少密钥的情况

    虽然这个版本

    function comparator_ok<T extends {[key in K]: unknown}, K extends keyof T>(key: K) {
        return (a: T, b: T) => a[key] === b[key] ? 0 : (a[key] > b[key] ? 1 : -1)
    }
    

    工作正常(我还是不太明白keyof T[key in K] 之间的区别似乎

    这是一个完整的例子:

    function comparator_bad<T, K extends keyof T>(key: K) {
        return (a: T, b: T) => a[key] === b[key] ? 0 : (a[key] > b[key] ? 1 : -1)
    }
    
    function comparator_ok<T extends {[key in K]: unknown}, K extends keyof T>(key: K) {
        return (a: T, b: T) => a[key] === b[key] ? 0 : (a[key] > b[key] ? 1 : -1)
    }
    
    let items = [
        { name: 'aaa', age: 99 },
        { name: 'ccc', age: 42, color: 'black' },
        { name: 'bbb', age: 40 },
    ]
    
    console.log({ by_age_with_comparator_bad: items.sort(comparator_bad('age')) })
    console.log({ by_age_with_comparator_ok: items.sort(comparator_ok('age')) })
    
    // no problem for ts in here :-(
    console.log({ by_color_with_comparator_bad: [...items].sort(comparator_bad('color')) })
    
    // with this this one ts complains!
    console.log({ by_color_with_comparator_ok: [...items].sort(comparator_ok('color')) })
    
    /*
    error:
    
    Argument of type '(a: { color: unknown; }, b: { color: unknown; }) => 0 | 1 | -1' 
    is not assignable to parameter of type 
    '(
      a: { name: string; age: number; color?: undefined; } | 
         { name: string; age: number; color: string; }, 
      b: { name: string; age: number; color?: undefined; } | 
         { name: string; age: number; color: string; }
    ) => number'.
    
      Types of parameters 'a' and 'a' are incompatible.
    
        Type '
          { name: string; age: number; color?: undefined; } | 
          { name: string; age: number; color: string; }' 
        is not assignable to type '{ color: unknown; }'.
      
          Type '{ name: string; age: number; color?: undefined; }' is not assignable to type '{ color: unknown; }'.
      
            Property 'color' is optional in type '{ name: string; age: number; color?: undefined; }' but required in type '{ color: unknown; }'.
    */
    

    ts playground

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-28
      • 2019-11-13
      • 1970-01-01
      • 2014-02-19
      • 2022-01-10
      • 2020-02-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多