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



从高层次来看,我试图定义一个通用类型,接受两种类型:

  • 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

您没有指定Data的形状。TypeScript不知道用任何键索引data会导致Result类型的结果。

很难知道以下解决方案是否适用于您的用例,但是您可以向Dataextends 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]
}

也许你可以添加一些例子,你调用函数,看看这是否适合所有的用例?

最新更新