返回函数时无法推断类型

时间:2020-02-28 08:42:04

标签: typescript

我有两个具有相同功能的版本;对于第一个(下面的propEq),typescript可以推断出key参数可以并且应该是类型为T的对象的键。

对于第二个功能(下面的propEq2),key的类型为never。如果我显式提供类型参数,它将毫无问题地工作。我猜这是因为propEq2的第一部分仅知道调用后T的类型,我知道为什么会有问题。但是即使我在对象上调用它,我仍然会遇到相同的错误。

我可以通过任何方式正确键入这种功能吗?

export const propEq = <T, K extends keyof T>(key: K, equals: T[K], object: T) => object[key] === equals;
export const propEq2 = <T, K extends keyof T>(key: K, equals: T[K]) => (object: T) => object[key] === equals;

1 个答案:

答案 0 :(得分:2)

因此,您面临的问题是-通过设计TS的工作方式。类型推断是从左到右,从上到下进行的。同样,这里的常识表明,无法实现您的要求,就像您说K extends keyof T之前Knever一样,直到知道T为止,就像设置键时没有对象一样却在类型级别提供了确切的信息,

type K = keyof unknown; // K is never

这就是为什么如果您首先提供K,则需要在T之前显式提供K,那么keyof T可以被评估为有意义的类型。

您也可以通过还原的方式进行操作,因此首先声明键和值,然后再将要求设置为对象,以其他方式进行。考虑以下:

const propEq = <K extends PropertyKey, V>(key: K, equals: V) => 
<T extends Record<K, V>>(object: T) => object[key] === equals;

propEq3('a', 1)({a: 2}) // yes correct
propEq3('a', 1)({a: 'str'}) // error as it should, `a` has different type
propEq3('a', 1)({b: 1}) // error as it should, there is no `a` in object

在这里做什么:

  • <K extends PropertyKey, V>我们说K是某种属性类型,而V是任何属性
  • KV两个参数都从keyequals推论得出
  • object被限制为T extends Record<K, V>,因此我们只允许比较具有此键和此类型值的对象

上述解决方案非常好,因为我们不将方程式限制为单一类型,但是我们新创建的propEq可以与任何具有想要的键和值类型的对象一起使用。