尝试了解TypeScript中的索引签名

时间:2019-08-03 11:06:59

标签: javascript typescript

我想我基本上了解了TypeScript中索引签名的工作方式。但是,有一件事我不明白。给出以下示例代码:

const sales: {[ key: string ]: number } = {
  a: 532,
  b: 798,
  c: 264
};

console.log(sales.a);
console.log(sales.d);

现在,编译器会说sales.asales.d的类型为number。但这不是number | undefined,因为编译器无法知道a和/或d是否确实存在吗?

在这里我无法提出特定的接口,因为ad在运行时是任意选择的,而不是预定义的。

我可以通过使用

解决此问题
{[ key: string ]: number | undefined }

作为一种类型,但这似乎既麻烦又烦人(考虑到JavaScript中通常如何使用对象,这对于一个非常琐碎的问题来说是一个相当la脚的解决方案)。

所以,有人可能会说:对我来说,这似乎违反直觉:如果索引签名实际上对地球上所​​有 个可能的字符串都具有强制意义,那么它具有什么意义呢?究竟是哪种类型?

实际上没有比提出一个更简单的解决方案了

{[ …: string ]: … | undefined }

一遍又一遍地输入?语言中没有任何东西吗?

考虑到存在Partial<T>和co之类的特产,这很难让人相信。 ……对此有何想法?

PS:Record<T>(在语义上)与{[ key: string ]: T | undefined }相同吗?

2 个答案:

答案 0 :(得分:5)

它已被raised as a suggestion并已被拒绝(尽管它被列为“等待更多反馈”),因为它预计会导致比其所能解决的错误更多的错误。您是对的,目前的情况是不一致的,并且在技术上不正确/不合理,但是not one of TypeScript's goals是“应用完善的或'证明正确的'类型的系统。相反,[应该]在正确性和生产率之间取得平衡。”

TypeScript实际上并没有强制匹配可能存在的所有可能存在 索引的键(因此索引签名属性实际上是可选的),但是它确实强制了任何这样的键,这些键 present具有正确类型的定义值...这是TypeScript中missing and undefined are distinguished少数几个地方之一。

如前所述,如果您希望自己的索引签名类型的行为与其他可选属性相同(意味着undefined自动是一个可能的值),则可以将| undefined添加到该属性中类型。如果希望现有的索引签名类型以这种方式运行(例如Array),则必须fork your own copy of the standard library and do it for yourself。他们不会在上游这样做,因为it would make lots of people very sad to deal with this

如果您真的希望看到这种情况发生变化,则可能需要visit the GitHub issue并进行评论或投票,但我不会屏住呼吸...您的时间可能最好花在克服这个问题上(我从经验...在处理TypeScript的实际不一致时,我不得不做几次。)

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

答案 1 :(得分:2)

这只是已接受答案的补充,因为它是完全正确的

如果您的目的是在不检查例如sales.d存在/不存在undefined,您可以在此处实现自己的接口:

interface SomeDictionary<T> {
  {[ key: string ]: T | undefined }
}

const sales: SomeDictionary<number> = {
  a: 532,
  b: 798,
  c: 264
};

// compile time error
const result = sales.a + sales.b;

// working
if(sales.a !== undefined && sales.b !== undefined){
  const result = sales.a + sales.b;
}

AFAIK在打字稿中没有这样的内置界面。

如果您要遍历此类对象的键,我认为索引签名(对于您而言)很有意义:

const sales: {[ key: string ]: number } = {
  a: 532,
  b: 798,
  c: 264
};

let sum = 0;
for(const key in Object.keys(sales)){
  sum = sum + sales[key];
}

我认为目前还没有想到更多用例。

对于您的另一个问题:不,不是(如果您是指here中的RecordRecord<T>甚至不能编译,因为它需要第二种类型的参数。我会说{ {1}}确实与您的问题无关。