为啥 TypeScript 对象不能用泛型类型索引?

Posted

技术标签:

【中文标题】为啥 TypeScript 对象不能用泛型类型索引?【英文标题】:Why can't TypeScript Objects index with generic types?为什么 TypeScript 对象不能用泛型类型索引? 【发布时间】:2017-08-04 01:06:13 【问题描述】:

javascript 中,普通的旧对象可能会受到各种滥用。例如你可以写:

var obj = ;
var func = new Function() ;
obj[func] = 5; // totally fine
obj[func]; // returns 5

通过一些创意,您可以编写一个泛型类SimpleSet<T>,它可能使用一个对象作为其在 JavaScript 或 TypeScript 中的后备存储。一种直接的方法可能涉及编写如下内容:

public add(val: T) 
  this._dict[val] = val;

这在 TypeScript 中不起作用。 为什么?更宽松的add 版本有效,请参阅add2add3

class SimpleSet<T> 
  _dict: Object;
  constructor() 

  

  // error:
  public add(val: T) 
    this._dict[val] = val;
  

  // no error:    
  public add2(val: T) 
    this._dict[val as any] = val;
  

  // no error:
  public add3(val: any) 
    this._dict[val] = val;
  

使用add,出现两个错误:

类型“T”不能分配给类型“Object[T]”。

类型“T”不能用于索引类型“对象”。

为什么?

【问题讨论】:

您的函数创建语法错误,但是您是否意识到将函数设置为 JS 对象的键会将函数强制转换为字符串,从而创建类似于这样的键:"function ()"?跨度> var obj = ; var key1 = prop1:'val1'; var key2 = prop2:'val2'; obj[key1] = "hello"; console.log(Object.keys(obj)); 将记录["[object Object]"]。记录obj[key2] 将显示“hello”,因为两个对象的toString() 相同。 你在一些不起作用的事情上已经走了很远...... 我并没有试图在这里制作一个可行的集合(这在 JS 中也很疯狂),而是试图找出允许any 与禁止Object 的规则类型。我现在看到我错误地认为any 的意思是“允许所有类型”,而不是“选择退出类型检查”。 【参考方案1】:

TypeScript 不让你这么做,因为它不起作用,就目前情况而言,这是一个相当不错的理由。

JavaScript 对象的索引键是 always (always) strings。通过其他类型的索引来强制字符串的键,然后通过它进行查找。例如,正如 cmets 中所指出的,按对象进行索引会产生键 "[object Object]"

您可以将 ES6 Map 对象用于有效的对象到值存储。

【讨论】:

感谢您的回答。我还在玩 TS,试图弄清楚什么是允许的,什么是不允许的。显然,这个 set 实现在 JS 中也很愚蠢。我认为 any 被允许作为索引类型很有趣,但 Object 不是。我现在看到我错误地认为 any 的意思是“允许所有类型”,而不是“选择退出类型检查”。

以上是关于为啥 TypeScript 对象不能用泛型类型索引?的主要内容,如果未能解决你的问题,请参考以下文章

Typescript 从具有泛型类型的对象索引调用函数

为什么要使用泛型?怎么用泛型?

为啥 TypeScript 有时只能通过字符串索引对象

Java泛型详解

为什么用泛型?

为啥 TypeScript 中的方法链接会导致泛型类型推断失败?