【问题标题】:destructuring a generic type in order to return an objects property解构泛型类型以返回对象属性
【发布时间】:2022-10-23 15:47:28
【问题描述】:

假设我有一个函数,它将 lambda 函数作为参数来访问/返回对象的属性,有没有办法对泛型进行解构(可能是递归的?)所以我知道该属性是否存在?我不希望将 T 扩展到任何现有类型,因为我希望使此函数输入类型尽可能通用

这是一个澄清的例子:

const binarySearch = <T, U>(array:T[], value:(T|U), getProperty?:(item:T, index?:number) => U):number => {}

其中“U”可以是“T”的任何一个属性

如果它是一个对象数组,则可以通过使用 lambda 访问属性来调用它

const index = binarySearch(objectArray, objectProperty, (obj) => obj.property)

或者如果不是,则使用数组值

const index = binarySearch(primitiveArray, primitive)

我希望该函数能够像普通的二进制搜索方法一样具有更多的通用性,因为不必创建几个类似的函数来访问不同的属性类型(特别是如果这些属性是嵌套的)

【问题讨论】:

  • 请提供一个使用示例以及您的期望。为什么项目是 T|U
  • @captain-yossarianfromUkraine 对不起,我匆匆完成了示例的命名变量和全面性,但我希望我的编辑能澄清一些事情。另外,T|U 是因为我希望能够根据数组搜索值或对象属性
  • 请提供一个带有实际值的示例,我需要它进行测试
  • 请考虑提供一个独立的minimal reproducible example,它会在将您的问题按原样粘贴到独立的 IDE 时演示您的问题。现在我的 IDE 不知道 objectArrayobjectPropertyprimitiveArrayprimitive 是什么,所以我必须尝试修复这些问题才能开始解决问题。如果您可以提前解决这些问题,并提供其他人可以测试的已知用例,那么您更有可能得到一个好的答案。如果您在问题中使用edit 并希望我再看一下,请发表评论并提及@jcalz,以便我收到通知。祝你好运!

标签: typescript typescript-generics


【解决方案1】:

您不需要将原语视为特殊情况。在这些情况下,只需传递getProperty 的标识函数:i =&gt; i

我对您的目标很感兴趣,可以自己制定一个通用解决方案,例如 1)一个数字数组以及 2)一个具有日期属性的对象数组:

const binarySearch = <T, U>(
  arr: T[], 
  getProperty:(item:T) => U, 
  searchedValue: U, 
  subArrayHeadIndex = 0, //for internal use w/recursion
): number | undefined => {
  const midPoint = Math.floor(arr.length / 2);
  const item = arr[midPoint];
  const propVal: U = getProperty(item);
  if(propVal === searchedValue){
    return subArrayHeadIndex + arr.indexOf(item);
  }
  const newStart = propVal > searchedValue ? 0 : midPoint + 1;
  const newEnd = propVal > searchedValue ? midPoint : arr.length;
  if (newStart === newEnd){
    console.log("couldn't find it")
    return -1
  }
  const newSubArrayHeadIndex = subArrayHeadIndex + (propVal > searchedValue ?  0: midPoint + 1);
  return binarySearch(arr.slice(newStart, newEnd), getProperty, searchedValue, newSubArrayHeadIndex);
}
  1. Primitives case -- 在以下数组中找到 29 的位置:
    const numbers = [2, 3, 6, 11, 13, 29, 35, 65, 89, 143, 144, 190, 2001];
    console.log(binarySearch(numbers, i => i, 29));
    // logs "5"
    
    1. 对象案例 -- 从数组中查找日期为 1995 年 8 月 21 日的项目的位置:
    const things = [
      { id: 1, date: 'January 17, 1995 03:24:00'},
      { id: 2, date: 'December 25, 1995 11:24:00'},
      { id: 3, date: 'January 27, 1995 05:43:00'},
      { id: 4, date: 'March 1, 1995 09:44:00'},
      { id: 5, date: 'April 10, 1995 13:20:00'},
      { id: 6, date: 'May 2, 1995 07:16:00'},
      { id: 7, date: 'May 24, 1995 15:55:00'},
      { id: 8, date: 'August 17, 1995 21:33:00'},
      { id: 9, date: 'August 21, 1995 21:49:00'},
      { id: 10, date: 'December 17, 1995 19:57:00'},
    ];
    
    const getDayString = (dateStr: string) => {
      const date = new Date(dateStr)
      //using Korean here for convenient comparison -- the KR format is "yyyy. mm. dd."
      const d= date.toLocaleDateString("ko-KR", {
        year: "numeric",
        month: "2-digit",
        day: "2-digit"
      });
      return d;
    }
    
    console.log(binarySearch(things, i => getDayString(i.date), "1995. 08. 21."))
    // logs "8"
    

【讨论】:

    【解决方案2】:

    我最终在处理其他一些功能时找到了自己的解决方案。

    getnestedkeys 类型函数不支持嵌套数组,因为我没有任何应用程序,但在检查属性类型是否为对象后,可能可以将其实现为第二个三元组

    但是我仍然更喜欢让 getproperty 参数是有条件的,只是不必总是为处理原始数组的任何调用键入 i => i,但这很容易改变

    这是我的代码:

    export type getNestedKeyTypes<T extends object> = {
        [K in keyof T]:T[K] extends object ? getNestedKeyTypes<T[K]> : K[keyof K]
    }[keyof T]
    
    export const binarySearch = <T, U, V = T extends object ? getNestedKeyTypes<T> : T>
    (arr:T[], value:V, getProperty?:(item:T) => (U&V)):number => {
        if(arr.length === 0) return -1
        const getArrayValue = (i:number) => getProperty ? getProperty(arr[i]) : arr[i]
        const getIndex = (upper:number, lower:number):number => {
            if(lower > upper) return -1
            const m = Math.round((upper+lower)/2)
            const av = getArrayValue(m)
            if(value === av) return m
            if(value > av) return getIndex(m-1, lower)
            return getIndex(upper, m+1)
        }
        return getIndex(0,arr.length-1)
    }
    

    【讨论】:

      猜你喜欢
      • 2021-06-11
      • 2021-01-30
      • 1970-01-01
      • 2018-07-09
      • 1970-01-01
      • 2011-02-02
      • 1970-01-01
      • 2022-01-01
      • 2021-08-11
      相关资源
      最近更新 更多