首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >类型记录:函数的约束参数,使其成为与特定类型的值关联的对象的键

类型记录:函数的约束参数,使其成为与特定类型的值关联的对象的键
EN

Stack Overflow用户
提问于 2018-09-05 15:08:11
回答 2查看 11.9K关注 0票数 17

是否有办法进行下列类型检查?

代码语言:javascript
运行
复制
function getNumberFromObject<T>(obj: T, key: keyof T): number {
  return obj[key] // ERROR: obj[key] might not be a number
}

我希望指定key不仅应该是T的一个键,而且应该是一个具有number值的键。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-09-05 15:46:49

要使调用方和getNumberFromObject<T>类型检查的实现都正确,最简单的方法是:

代码语言:javascript
运行
复制
function getNumberFromObject<T extends Record<K, number>, K extends keyof any>(
  obj: T, 
  key: K
): number {
  return obj[key] // okay
}

当你称之为:

代码语言:javascript
运行
复制
getNumberFromObject({dog: 2, cat: "hey", moose: 24}, "dog"); // okay
getNumberFromObject({dog: 2, cat: "hey", moose: 24}, "cat"); // error
getNumberFromObject({dog: 2, cat: "hey", moose: 24}, "moose"); // okay
getNumberFromObject({dog: 2, cat: "hey", moose: 24}, "squirrel"); // error

这一切都运行得很好,除了您得到的错误有点模糊,因为它抱怨Object literal may only specify known properties, and 'dog' does not exist in type 'Record<"somebadkey", number>'。这个抱怨是一个超额财产检查,并不是真正的问题。

如果要使调用方获得更好的错误,可以使用更复杂的条件类型

代码语言:javascript
运行
复制
function getNumberFromObject<T, K extends keyof any & {
  [K in keyof T]: T[K] extends number ? K : never
}[keyof T]>(
  obj: T,
  key: K
): T[K] {
  return obj[key] // okay
}

getNumberFromObject({ dog: 2, cat: "hey", moose: 24 }, "dog"); // okay
getNumberFromObject({ dog: 2, cat: "hey", moose: 24 }, "cat"); // error
getNumberFromObject({ dog: 2, cat: "hey", moose: 24 }, "moose"); // okay
getNumberFromObject({ dog: 2, cat: "hey", moose: 24 }, "squirrel"); // error

在这种情况下,T是不受约束的,但是K只能是来自T ( T[K]number )的键。

现在,错误说,Argument of type '"somebadkey"' is not assignable to parameter of type '"dog" | "moose"'.,这是更有利于开发人员。不过,不确定签名的额外复杂性是否值得您这么做。

希望这能有所帮助。祝好运!

Update:后一个函数返回T[K],而不是number。这可能是件好事,因为T[K]可能比number更具体。例如:

代码语言:javascript
运行
复制
interface Car {
  make: string,
  model: string,
  horsepower: number,
  wheels: 4
}
declare const car: Car;
const four = getNumberFromObject(car, 'wheels'); // 4, not number

four的类型是4,它比number更具体。如果您真的想将函数的返回类型扩展到number,您可以.尽管实现会对此犹豫不决,因为编译器不够聪明,无法意识到在一般情况下T[K]是可以分配给number的。有处理这些问题的方法,但最简单的方法是在实现中使用类型断言(return obj[key] as any as number)。

操场链接到代码

票数 24
EN

Stack Overflow用户

发布于 2021-10-01 13:57:04

最佳解决方案:

代码语言:javascript
运行
复制
const getNumberFromObject = <T extends Record<K, number>, K extends keyof T>(
  obj: T,
  key: K,
) => {
  return obj[key];
};
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52188399

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档