如何使用TypeScript使curried getter函数类型安全?

时间:2017-01-10 20:10:07

标签: typescript

我试图为以下功能编写类型

function get(prop) {
  return (obj) => obj[prop];
}

我最初尝试使用keyof,但我无法让它发挥作用。现在我得到了这个:

function get<K extends string>(prop: K) {
  return <V, T extends {K: V}>(obj: {K: V}) => obj[prop];
}

但它给出了错误

error TS2536: Type 'K' cannot be used to index type '{ K: V; }'.

因为{K: V}似乎有一个键K,所以看起来有点傻。

是否可以使函数类型安全,以便第一个参数必须是一个字符串,并且返回函数的参数必须是具有正确属性的对象?

更新:感谢您的回答。但是,这两种解决方案都存在问题。请考虑以下代码:

function get<K extends string>(prop: K) {
  return <V, Obj extends Record<K, V>>(obj: Obj): Obj[K] => obj[prop];
}
const a = get("foo")({ foo: 1 });
a + 12;

最后一行导致错误,因为TypeScript推断出{}的{​​{1}}类型。这使得函数使用起来非常麻烦,因为必须强制转换a

2 个答案:

答案 0 :(得分:2)

它似乎至少适用于夜间构建:

function get<K extends string>(prop: K) {
  return <V, Obj extends Record<K, V>>(obj: Obj) => obj[prop];
}

答案 1 :(得分:1)

AlexG的answered确实有效。您也可以在没有Record的情况下执行此操作。这里的代码说明了两者。 get使用Record<K, V>get2使用{[x in K]: V}

function get<K extends string>(prop: K) {
  return <V, Obj extends Record<K, V>>(obj: Obj) => obj[prop];
}

function get2<K extends string>(prop: K) {
  return <V, T extends {[x in K]: V}>(obj: T) => obj[prop];
}

const foo = {
  "a": 1,
  "b": 2,
};

console.log(get("b")(foo));
console.log(get2("b")(foo));
// This line should compile fine in recent development versions and
// presumably will work fine in regular releases from 2.2.0 onwards.
// There's a bug in 2.1.x that causes the type inference to bork and 
// cause the compiler to think were adding 1 to a plain object (`{}`).
console.log(get2("b")(foo) + 1);

我想到了上面的内容然后虽然get2我可能正在复制Record做的事情和lo and behold,但情况就是这样,因为Record被定义为这样:

/**
 * Construct a type with a set of properties K of type T
 */
type Record<K extends string, T> = {
    [P in K]: T;
}

您在更新中提到的类型推断问题是TypeScript中的一个错误,该错误已在相对较新版本的TypeScript中修复。 (Alex mentions版本2.2.0-dev.20161221。我尝试过更新的版本,并且还获得了完美的编译。)据推测,它将在版本2.2.0中修复。我不知道任何解决方案会修复2.2.0之前的版本中的编译错误,并且不会有其他负面副作用。