具有索引类型的 TypeScript 泛型柯里化函数

Dan*_*rke 5 functional-programming typescript

我创建了一个 TypeScript 柯里化函数,它首先接收字符串形式的属性名称,然后接收从中获取该属性值的对象。我使用索引类型来确保每当我尝试访问不存在的属性时都会收到错误:

export interface Dict {
  name: string;
  age: number;
}

const prop = <T extends Dict, K extends keyof T>(p: K) => (obj: T): T[K] => obj[p];

prop('name')({name: 'John', age: 45});  // John
prop('name2')({name: 'John', age: 45});  // error...
Run Code Online (Sandbox Code Playgroud)

最后一行给出了错误:

error TS2345: Argument of type '"name2"' is not assignable to parameter of type '"name" | "age"'.
Run Code Online (Sandbox Code Playgroud)

这正是我想要的,因为name2作为第二个参数给出的对象上不存在该属性。

然而,当我尝试使用 Maybe monad 创建安全版本时,它给出了类似的错误:

const safeProp = <T extends Dict, K extends keyof T>(p: K) => (obj: T): Maybe<{}> => compose2(Maybe.of, prop(p))(obj);
Run Code Online (Sandbox Code Playgroud)

错误出现在函数的第二个参数上compose2::prop(p)

Argument of type 'K' is not assignable to parameter of type '"name" | "age"'.
Run Code Online (Sandbox Code Playgroud)

我不明白,因为我已经声明了K extends keyof T我认为是正确的,因为它也适用于该prop函数。

作为参考,该compose2函数:

const compose2 = <A, B, C>(f: (b: B) => C, g: (a: A) => B): ((a: A) => C) => a => f(g(a));
Run Code Online (Sandbox Code Playgroud)

以及 monad 的相关部分Maybe:

class Maybe<A> {
  static of<A>(x: A): Maybe<A> {
    return new Maybe(x);
  }

  ...
}
Run Code Online (Sandbox Code Playgroud)

如何正确键入safeProp函数以及为什么需要将其返回类型指定为Maybe<{}>和 not Maybe<T[K]>?

y2b*_*2bd 1

这里有一个问题,详细说明了在将泛型函数传递到泛型高阶函数时(在您的情况下,传递Maybe.of<A>到compose2<A,B,C>),Typescript 如何无法正确推断类型。

compose2您可以通过在使用时手动填写类型来缓解这种情况。

const safeProp = <T extends Dict, K extends keyof T>(p: K) => (obj: T) => compose2<T, T[K], Maybe<T[K]>>(Maybe.of, prop(p))(obj);
Run Code Online (Sandbox Code Playgroud)

safeProp现在有了正确的类型const safeProp: <T extends Dict, K extends keyof T>(p: K) => (obj: T) => Maybe<T[K]>。