代码之家  ›  专栏  ›  技术社区  ›  casperOne

将参数限制为返回类型值的类型键或执行相同操作的函数

  •  0
  • casperOne  · 技术社区  · 2 年前

    从高层来看,我试图定义一个采用两种类型的泛型类型:

    • T-类型
    • V-使用键T访问T时返回的值的类型

    这样,它允许以下方面的联合:

    • 返回类型V的任何类型T的键
    • 一个函数,它取T类型的实例并返回V类型的值

    为此,我定义了以下内容:

    type KeysWithValueOfType<T, V> = {
        [K in keyof T]-?: Exclude<T[K], undefined | null> extends V ? K : never
    }[keyof T]
    

    以下内容如下:

    https://stackoverflow.com/a/54520829/50776

    然后,我定义了一个选择器类型,它是键和函数访问器的并集:

    type Selector<T, V> = KeysWithValueOfType<T, V> | ((t: T) => V)
    

    在这一点上,当我试图创建一个泛型函数来将访问器解析为给定类型为T的实例的值时,我希望

    function getValue<Data extends Aggregate, Result>(
        selector: Selector<Data, Result>,
        data: Data
    ): Result {
        // If a function, evaluate, otherwise, use as a key
        // into the object.
        return typeof selector === 'function' ? selector(data) : data[selector]
    }
    

    但是,它给了我以下错误:

    Type 'Result | Data[KeysWithValueOfType<Data, Result>]' is not assignable to type 'Result'.
      'Result' could be instantiated with an arbitrary type which could be unrelated to 'Result | Data[KeysWithValueOfType<Data, Result>]'.ts(2322)
    

    如果我尝试分解三元运算符:

    function getValue<Data extends Aggregate, Result>(
        selector: Selector<Data, Result>,
        data: Data
    ): Result {
        // If the accessor is a string, evaluate and return it.
        if (typeof selector === 'function')
            return selector(data)
    
        // Use the accessor
        return data[selector]
    }
    

    它看起来像一条线:

    return data[selector]
    

    我得到了一个稍微不同的信息:

    Type 'Data[KeysWithValueOfType<Data, Result>]' is not assignable to type 'Result'.
      'Result' could be instantiated with an arbitrary type which could be unrelated to 'Data[KeysWithValueOfType<Data, Result>]'.ts(2322)
    

    有没有办法实现我想要的目标?

    我目前正在使用Typescript 4.6.3。

    我还创建了一个显示问题的代码沙盒,错误在 getValue 接近尾声:

    https://codesandbox.io/s/selector-example-0gbfhm?file=/src/index.ts

    1 回复  |  直到 2 年前
        1
  •  0
  •   Tobias S.    2 年前

    您没有指定的形状 Data .TypeScript不知道 data 使用任何键进行索引都将导致类型为的结果 Result

    很难知道以下解决方案是否适用于您的用例,但您可以向 数据 extends Record<string, Result> :

    function getValue<Data extends Record<string, any>, Result>(
        selector: Selector<Data, Result>,
        data: Data
    ): Result {
        // If the accessor is a string, evaluate and return it.
        if (typeof selector === 'function')
            return selector(data)
    
        // Use the accessor
        return data[selector]
    }
    

    也许您可以添加一些调用函数的示例,看看这是否适用于所有用例?