我想制作一个方法,从我的自定义对象类型返回一个新对象。
/*
type K represent the type of key in an object
type V represent the type of value in an object
*/
class Group<K,V> extends Map<K,V> {
toObject() {
const result: { [key in keyof K]: V } = {} as { [key in keyof K]: V }
for (const [key, value] of this.entries()) {
result[key] = value //Error:Type 'K' cannot be used to index type '{ [key in keyof K]: V; }'.ts(2536)
}
return result
}
}
key 和 value 的类型分别是 K 和 V。
我不太明白错误信息,如果你能给我解释一下就好了。
我也试着让它变得更容易。
class Group<K, V> extends Map<K, V> {
toObject() {
const result = {}
for (const [key, value] of this.entries()) {
result[key] = value //Error:Type 'K' cannot be used to index type '{}'.ts(2536)
}
return result
}
}
最佳答案
这里的主要问题是您使用的是 keyof K
而不仅仅是 K
. The keyof
type operator给你 union它适用的类型的键(通常是 literal type 类似于 "a"
)。 keyof {a: 1, b: 2, c: 3}
是"a" | "b" | "c"
.所以keyof K
将是您期望 K
类型值的任何键拥有。如果K
类似于 string
, 然后 keyof K
类似于 keyof string
这是:
type KeyofString = keyof string;
/* type KeyofString = number | typeof Symbol.iterator | "toString" | "charAt" |
"charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" |
"match" | "replace" | "search" | "slice" | "split" | "substring" |
"toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" |
"trim" | "length" | "substr" | "valueOf" | "codePointAt" | "includes" |
"endsWith" | "normalize" | "repeat" | "startsWith" | "anchor" | "big" |
"blink" | "bold" | "fixed" | "fontcolor" | "fontsize" | "italics" |
"link" | "small" | "strike" | "sub" | "sup" | "padStart" | "padEnd" */
除非你想要result
拥有像"toUpperCase"
这样的 key 或 "trim"
, 然后 keyof K
是不对的。
如果result[key]
有道理,如果key
类型为 K
, 那么你想要一个可以使用 K
类型的键索引的类型.如果你输入一个值 value
类型 V
进入那个属性,那么你想要一个类型,其值是 V
类型. mapped type {[P in K]: V}
就是这样一种;键是 K
值是 V
.这种值类型不依赖于特定键的映射类型通常称为“记录”,并且经常使用,以至于有一个 Record<K, V>
utility type。为此目的而提供。
让我们使用Record<K, V>
然后:
class Group<K, V> extends Map<K, V> {
toObject() {
const result = {} as Record<K, V>; // error!
// -----------------------> ~
// Type 'K' does not satisfy the constraint 'string | number | symbol'
for (const [key, value] of this.entries()) {
result[key] = value // okay
}
}
}
所以,这解决了 result[key] = value
错误,但它引入了一个新的错误。类型Record<K, V>
是 K
中的错误, 其中K
不满足作为类键类型的约束,string | number | symbol
.注意 string | number | symbol
经常使用,所以还有一个 PropertyKey
提供的实用程序类型是为此的短别名。
如果您的 Group<K, V>
确实是个问题K
确实可以有任意 类型. Map
object在 JavaScript 中可以保存任何类型的“键”,而像 result
这样的普通对象只能容纳 PropertyKey
的键类型。例如,您可以使用 Date
对象作为 Map
的“键”但不能作为普通 JavaScript 对象的键:
const date = new Date();
const m = new Map<Date, string>();
m.set(date, "hello"); // okay
const o: any = {};
o[date] = "hello"; // error
因此,如果您的 Group<K, V>
确实需要 Record<K, V>
类型的值,那么这意味着你必须 constrain K
这样编译器只会让new Group<K, V>
K
时存在足够关键:
class Group<K extends PropertyKey, V> extends Map<K, V> {
toObject() {
const result = {} as Record<K, V>; // okay
for (const [key, value] of this.entries()) {
result[key] = value // okay
}
}
}
现在一切都按需要编译。
关于typescript - 类型 'K' 不能用于索引类型 '{ [key in keyof K]: V; }' .ts(2536),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71517678/