具有索引类型的 TypeScript 通用柯里化(Currying)函数

标签 typescript functional-programming

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

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...

最后一行报错:

error TS2345: Argument of type '"name2"' is not assignable to parameter of type '"name" | "age"'.

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

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

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

错误在 compose2 的第二个参数上功能:prop(p) :

Argument of type 'K' is not assignable to parameter of type '"name" | "age"'.

我不明白,因为我已经声明了 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));

Maybe的相关部分单子(monad):

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

  ...
}

如何正确输入 safeProp函数以及为什么我需要将其返回类型指定为 Maybe<{}>而不是 Maybe<T[K]>

最佳答案

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

上面的代码不会给你一个错误,我会试着解释为什么(以及为什么你的代码会)。

K extends keyof Dict 恰好是 nameage(这仅是函数 prop 允许的参数) .和 K extends keyof T 实际上可以是 any number | 类型的键 |字符串 |符号。因为如果 T extends Dict,这并不意味着它不能有任何其他键,如“lastname”等。换句话说:

type IsDict = {name: string, age: number, lastname: string} extends Dict ? true : false // IsDict is true

看到了吗?您的代码将允许使用 lastname 键,而 Typescript 会保护您不这样做。

也就是说, typescript 目前 does not have将类型参数限制为精确类型的方法(有 workarounds 但遗憾的是它们不适合您的情况)。

关于具有索引类型的 TypeScript 通用柯里化(Currying)函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53824319/

相关文章:

typescript - 如何将属性添加到 typescript 中的现有类型?

javascript - Angular -"changingThisBreaksApplicationSecurity"给出 ts 错误 "Property ' waitingThisBreaksApplicationSecurity' 在类型 'SafeUrl' 上不存在。”

algorithm - 用于查找范围的可变变量 Racket

clojure - 为什么更多的语言不使用像 Clojures 这样的不可变模型?

functional-programming - 已安装 ocamlfind (findlib),但在 Mac 中始终找不到任何额外的包

Java 8 将列表按涉及先前元素的条件分组

angular - 每 X 秒调用一个函数

Javascript正则表达式查找两个分隔符之间的两个字符

javascript - 在推送对象时,我得到的所有内容都是 NULL angular2+typescript

list - 如何找到具有最小值的元素的索引?