我有下面的函数,根据过滤函数过滤对象的 prop :
function filterProps<K extends string, V>(object: Record<K, V>, fn: (key:K, value: V, object: Record<K, V>) => unknown) {
// return a new object with only the properties filtered by fn
return Object.entries(object).reduce(
(acum, [key, value]) => fn(key, value, object) ? {...acum, [key]: value } : acum,
{} as Record<K, V>
)
}
我得到错误:
(parameter) key: string
Argument of type 'string' is not assignable to parameter of type 'K'.
'string' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string | number | symbol'.(2345)
应该如何键入"key
"以避免该错误?
注:此处提供Playground
1条答案
按热度按时间31moq8wy1#
the
Object.entries()
static method的TypeScript类型为这两个函数都返回一个键值元组数组,其中键的类型为
string
。没有得到K
的原因是TypeScript中的对象类型不是"密封的"或"精确的"(如microsoft/TypeScript#12936中所要求的);一个对象总是有可能拥有比TypeScript所知道的更多的属性。有关Object.keys()
返回string[]
的类似问题/答案,请参见Why doesn't Object.keys return a keyof type in TypeScript?。例如,可能会出现以下情况:
注意赋值
const y: Foo = x
是如何成功的;这是因为x
包含了Foo
中所需的所有属性,并且 * 多余的属性不会使赋值无效 *。对于像const y: Foo = { bar: "abc", baz: "def", qux: 123 }
这样的 * 对象常量 *,存在多余的属性检查,但这会失败,因为关于qux
的信息将完全被编译器遗忘(因此被认为是错误),而不是因为qux
违反了任何东西。这意味着
filterProps()
方法实现在技术上是不安全的,因为我可以写这错误地假设
v
将是string
类型。调用编译没有错误,因为filterProps()
的调用签名允许它,但随后实现最终将number
视为string
,并且您得到运行时错误。所以才会有错误。你所做的在技术上是不安全的。
如果你确信你的对象实际上不会有这种意外类型的多余属性,那么你可以向编译器Assert,一种方法是Assert
Object.entries(object)
返回Array<[K, V]>
,如下所示:现在实现编译无误了,因为编译器假设您知道自己在做什么,并且
Object.entries(object)
将返回一个Array<[K, V]>
,正如您所声明的那样。这并没有使函数变得更安全,因为您仍然可以调用
filterProps(y, (k, v) => v.toUpperCase() === v)
,但是类型Assert将防止这种情况发生的责任从编译器转移到了您身上,所以继续操作要自担风险!Playground代码链接