typescript - 类型 'K' 不能用于索引类型 '{ [key in keyof K]: V; }' .ts(2536)

标签 typescript

我想制作一个方法,从我的自定义对象类型返回一个新对象。

/*
    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
    }
  }
}

现在一切都按需要编译。

Playground link to code

关于typescript - 类型 'K' 不能用于索引类型 '{ [key in keyof K]: V; }' .ts(2536),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71517678/

相关文章:

javascript - 如何使用 httpClient 从 Angular 中的可观察对象访问数据?

html - 如何使 ng2-charts 垂直条形图水平滚动?

typescript - 如何在TypeScript中编写不包含空字符串的字符串类型

typescript - 防止创建类型别名实例

reactjs - 输入 mapStateToProps React Redux

Angular CLI 在更改路由时刷新内容

typescript - Winston 自定义日志级别 typescript 定义

android - Visual Studio Cordova 工具,错误文件中的设备调试断点

Angular io(4) *ngFor first and last

typescript - 如何使用 VSCode api 打开自定义编辑器