如何扩展 keyof 类型以使其包含密钥的修改版本,例如前缀为“-”?

2024-01-26

例如,我想将 Typescript 类型安全添加到普通 Javascript 中按字符串属性值对对象数组进行排序 https://stackoverflow.com/a/4760279/13815493解决方案。它接受要排序的对象的键作为 args,以确定按哪个键排序。如果密钥前缀为-,排序相反。

我该如何输入 arg 来接受,例如,两者"age" and "-age"?

这是我的尝试:

export function dynamicSortMultiple<T extends object, U extends keyof T>(
  props: Array<U>,
) {
  function dynamicSort(key: U) {
    let sortOrder = 1
    if (typeof key === 'string' && key.startsWith('-')) {
      sortOrder = -1
    }
    return function (a: T, b: T) {
      const result = a[key] < b[key] ? -1 : a[key] > b[key] ? 1 : 0

      return result * sortOrder
    }
  }

  return function (obj1: T, obj2: T) {
    let i = 0
    let result = 0
    const numberOfProperties = props?.length
    while (result === 0 && i < numberOfProperties) {
      result = dynamicSort(props[i])(obj1, obj2)
      i++
    }

    return result
  }
}

export interface User {
  userId: string
  firstName: string
  lastName: string
  login: string
  password: string
  rank: number
  score: number
  age?: number
}

dynamicSortMultiple<User, keyof User>(['firstName', 'score', '-age'])

打字稿游乐场 https://www.typescriptlang.org/play?#code/KYDwDg9gTgLgBAMwK4DsDGMCWEVwCYCeKAhgLaZoDK0MAskgDZZgPAA8AKnKDMCngGc4EAEYArYBgA0cAKrcQvfkIDWwAhARwOAPgAUAWABQcOGCgQwAgFxwAglCjECbWTqnGAlHADex08joWDj4RGQU1LB6agS2st5+JqZwrPACNADyUHjAUHAAvHAAjP7JmFp6MARgwJpwMQX5hQDkAjBQmCgA5s1wAGR99eoAdG3EsAIA6pgwABZ6zQC0zZ4Jpclw6bBZOXmFiyVJpgC+63BQwDBIULiBGNi4esS2HDIiL2tHyWg4befAAkY8EKxAA2jEALpwNhwETg9RQgD8cAOcFsYMhcB0sPhBCRxTRcAADMYzqYLlcbv9AUw4AAqTaZbK5M6nJJs0oU663VD3EJ6URiIovGSCgBMH18Z1ScEwBWJ0su1KB8pJXx+KD+KCQpBEuQyCAAChYarBMAD5eZLAJEcNWN05mcAO6zTCsOB6C404FNYn9QZymHa3X6o0m3JYAGfDbkgEqwqEEjkKg0PRWqygzAQzwC8RFUXiMWeMmygDUpdZpK+XKpXqBpTZHKMoEgsFlKF4UAQxDQwDkAlyUqSSAHUAAknhbG0Ot1SghMFA2gA5MjAKftTpdUoMYjL1frmdbpIMCBdToHzelMC7gRO6CTzYb2dJJwoFS2YN6qClAQ-C4fnUv1KYgumAREAJDb8jCbRNwhTWB6CYTAWHYWRRxkGI6jQ3J9FBZp50XGAV1IYBmhkVo-1I8jFhA0jsyAA

在最后一行我看到错误

Type '"-age"' is not assignable to type 'keyof User'.

有什么办法可以延长keyof User正确地使带有“-”前缀的值仍然被视为该类型的有效值?

即使您完全替换我的解决方案,我也会感激任何解决方案。


我的改变:

  1. T 和 U 通用参数是多余的。只需要T。

    注意:我最初只是替换了你所有的U参考文献与keyof T,但随后将其拉出sortArg促进 #2.

  2. use 模板文字类型 https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-1.html#template-literal-typesTS 4.1 中引入

  3. 你忘了修剪-startsWith('-') 情况下的前缀

  4. 在 Typescript 无法缩小类型的情况下使用类型断言 必须给出逻辑流程(TS 团队一直在改进 TS 编译器的流程分析,所以我敢打赌有一天这将是自动的)

  5. API改进:重命名了函数并添加了方便的sort函数在代码中可读性更好(请参阅示例用法 位于解决方案代码之后)。

type sortArg<T> = keyof T | `-${string & keyof T}`

/**
 * Returns a comparator for objects of type T that can be used by sort
 * functions, were T objects are compared by the specified T properties.
 *
 * @param sortBy - the names of the properties to sort by, in precedence order.
 *                 Prefix any name with `-` to sort it in descending order.
 */
export function byPropertiesOf<T extends object> (sortBy: Array<sortArg<T>>) {
    function compareByProperty (arg: sortArg<T>) {
        let key: keyof T
        let sortOrder = 1
        if (typeof arg === 'string' && arg.startsWith('-')) {
            sortOrder = -1
            // Typescript is not yet smart enough to infer that substring is keyof T
            key = arg.substr(1) as keyof T
        } else {
            // Likewise it is not yet smart enough to infer that arg here is keyof T
            key = arg as keyof T
        }
        return function (a: T, b: T) {
            const result = a[key] < b[key] ? -1 : a[key] > b[key] ? 1 : 0

            return result * sortOrder
        }
    }

    return function (obj1: T, obj2: T) {
        let i = 0
        let result = 0
        const numberOfProperties = sortBy?.length
        while (result === 0 && i < numberOfProperties) {
            result = compareByProperty(sortBy[i])(obj1, obj2)
            i++
        }

        return result
    }
}

/**
 * Sorts an array of T by the specified properties of T.
 *
 * @param arr - the array to be sorted, all of the same type T
 * @param sortBy - the names of the properties to sort by, in precedence order.
 *                 Prefix any name with `-` to sort it in descending order.
 */
export function sort<T extends object> (arr: T[], ...sortBy: Array<sortArg<T>>) {
    arr.sort(byPropertiesOf<T>(sortBy))
}

用法示例:

interface User {
    name: string
    id: string
    age?: number
}

const users: User[] = [
    {name: 'Harriet Tubman', id: '01', age: 53},
    {name: 'John Brown', id: '02', age: 31},
    {name: 'John Brown', id: '03', age: 59},
    {name: 'James Baldwin', id: '04', age: 42},
    {name: 'Greta Thunberg', id: '05', age: 17}
]

// using Array.sort directly 
users.sort(byPropertiesOf<User>(['name', '-age', 'id']))

// using the convenience function for much more readable code
sort(users, 'name', '-age', 'id')
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何扩展 keyof 类型以使其包含密钥的修改版本,例如前缀为“-”? 的相关文章

随机推荐

  • 避免循环内的条件和函数调用

    我有一个看起来像这样的代码 void function int parameter for a big loop double a for a big loop double b double value if parameter 1 va
  • Python + MySQLdb 执行许多

    我正在使用 Python 及其 MySQLdb 模块将一些测量数据导入 Mysql 数据库 我们拥有的数据量相当大 目前大约有 250 MB 的 csv 文件 未来还会有更多 目前我使用cursor execute 导入一些元数据 这不是问
  • kubectl 端口转发和代理之间的区别

    kubectl proxy and kubectl port forwarding对我来说看起来相似且令人困惑 它们的主要区别和用例是什么 正如 How kubectl port forward works https stackoverf
  • 在 Java 中使用命名空间创建 XML 文档

    我正在寻找可以构造使用命名空间的 XML 文档的示例 Java 代码 我似乎无法用我的正常方式找到任何东西最喜欢的工具 http www google com所以希望有人能够帮助我 有多种方法可以做到这一点 仅举几个例子 Using XOM
  • 如何将react应用程序导出为纯静态html

    就像标题一样 我有一个由reactJS编写的登陆页面 它很小 我想导出为纯静态html 我已经研究过 但没有找到任何解决方案 I used webpack https webpack js org 生成静态 html 和 javascrip
  • Rails3 gem:acts_as_something

    我正在尝试将一些常见代码提取到 gem 中 我在想acts as something是简单重用的好策略 有没有一个很好的教程来讨论这个关于rails3 gems 的问题 我发现了几个讨论rails2的 例如http guides rubyo
  • 如何忽略转义\ python列表?

    我想忽略以下代码中的转义字符 gt gt gt a gt gt gt print a 我想输出像 有什么办法可以做到这一点吗 Using string escape unicode escape编码 参见Python 特定编码 http d
  • React - 动态渲染一定数量的组件

    我想根据用户获得的积分数显示组件星号 MUI 组件 的数量 this state points 我不知道该怎么做 import React Component from react import Star from material ui
  • 使用拼凑时如何减少图之间的空间

    大家好 我正在使用一个小数据框来构建一些图ggplot2 我的数据框是df我把它包括为dput 在最后 我有情节 当我使用时问题出现patchwork 我希望最终的图没有空格 以便中间的线 即轴 可以将图连接在一起 这是代码 library
  • ITfoxtec SAML 2.0:配置 AWS SSO 时出现 InvalidSignatureException

    我有一个小型测试应用程序 已成功与 Okta 作为 IdP 集成 我还设置了 AWS SSO 来充当 IdP 当我将应用程序切换为使用 AWS SSO 时 出现以下错误 ITfoxtec Identity Saml2 Cryptograph
  • 测试对象是否实现接口

    以前可能有人问过这个问题 但快速搜索只提出了与 C 相同的问题 看这里 https stackoverflow com questions 410227 test if object implements interface 我基本上想做的
  • 根据另一个值的聚合查询唯一值,同时完全根据第三个值进行分组

    所以我知道这个问题并不是一个新问题 但我正在努力解决这个问题并了解处理此类情况的最佳方法 假设我有一个假设的表 X 如下所示 GroupID ID identity SomeDateTime 1 1000 1 1 01 1 1001 2 2
  • C 中的 OO 多态性、别名问题?

    我和一位同事正在尝试实现一个简单的多态类层次结构 我们正在开发嵌入式系统 并且仅限于使用 C 编译器 我们有一个基本的设计思想 可以在没有警告的情况下进行编译 Wall Wextra fstrict aliasing pedantic 并在
  • iOS 8 UITabBarController 和 UINavigationController 的旋转问题

    我在使用 iOS8 时遇到一个问题 这里我有我的视图层次结构 窗口 gt UITabBarController gt 2 个选项卡 Tab 1 gt UINavigationController1 gt UIViewController1
  • 通过 set/get 方法修改类

    尝试通过 get set 方法修改类中的对象 我无法理解如何仅使用 get set 方法来更改值 预期输出 输出 89 实际输出 输出 0 include
  • 如何在 Web 应用程序中获取客户端计算机的 Mac 地址

    我必须获取运行我的网站的客户端 PC 的 Mac 地址 那么如何获取客户端计算机的 Mac 地址 而不是托管网站的服务器的 Mac 地址 我需要与 IE Firefox Safari 和 Chrome 兼容的脚本 实现这一点的唯一方法是使用
  • 如何在 Cassandra 中将批处理语句和 LWT 作为事务执行

    我有两个模型如下的表 CREATE TABLE IF NOT EXISTS INV CODE TEXT PRODUCT CODE TEXT LOCATION NUMBER TEXT QUANTITY DECIMAL CHECK INDICA
  • 约束布局 - Textview 在尺寸增大时会与其他视图重叠

    上图显示了我想要的视图的样子 问题是 当上重力文本尺寸增加时 它会将图像推离视图 我尝试使用障碍 但无法使其发挥作用 下图显示了我在实现这一目标方面已经走了多远 但现在的问题是图像总是卡在最后 但我希望它位于重力文 本旁边 当该文本增加时
  • 与 import python 有点困惑

    我有 PHP 以及其他一些东西 背景 并且正在使用 Python 在 PHP 中 当我想包含另一个文件时 我只需这样做include or require并且该文件中的所有内容都包含在内 但似乎在 python 中做事情的推荐方法是from
  • 如何扩展 keyof 类型以使其包含密钥的修改版本,例如前缀为“-”?

    例如 我想将 Typescript 类型安全添加到普通 Javascript 中按字符串属性值对对象数组进行排序 https stackoverflow com a 4760279 13815493解决方案 它接受要排序的对象的键作为 ar