简体   繁体   English

TypeScript 中的索引签名不处理未定义的

[英]Index signatures in TypeScript don't handle undefined

I think I basically got how index signatures work in TypeScript.我想我基本上了解了索引签名在 TypeScript 中的工作原理。 However, there is one thing I don't get.但是,有一件事我不明白。 Given the following sample code:给定以下示例代码:

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

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

Now the compiler says, sales.a and sales.d are of type number .现在编译器说sales.asales.d的类型是number But shouldn't that be number | undefined但那不应该是number | undefined number | undefined , since the compiler can not know if a and / or d are actually there? number | undefined ,因为编译器无法知道a和/或d是否真的存在?

I can't come up with a specific interface here, because a and d are arbitrarily chosen at runtime, and not predefined.我这里想不出具体的接口,因为ad是在运行时任意选择的,而不是预定义的。

I can solve this by using我可以通过使用解决这个问题

{[ key: string ]: number | undefined }

as a type, but this seems to be cumbersome and annoying (and a pretty lame solution for a pretty trivial problem, given how objects are typically used in JavaScript).作为一种类型,但这似乎既麻烦又烦人(考虑到对象通常在 JavaScript 中的使用方式,对于一个非常琐碎的问题来说,这是一个相当蹩脚的解决方案)。

So, one could say: To me, this seems counterintuitive: What sense do index signatures have, if they virtually enforce that for every possible string on earth there is also a value?所以,有人可以说:对我来说,这似乎违反直觉:如果索引签名实际上强制地球上每个可能的字符串也有一个值,那么索引签名有什么意义? For which type is this ever true?这对哪种类型来说是真的?

Is there actually no easier solution for this than to come up with a实际上,没有比想出一个更简单的解决方案了吗?

{[ …: string ]: … | undefined }

type over and over again?一遍又一遍地打字? Nothing integrated into the language?没有集成到语言中?

It's hard to believe that, given the fact that there are specialties such as Partial<T> and co.很难相信这一点,因为有Partial<T>和 co 等专业。 … any thoughts on this? ……对此有什么想法吗?

PS: Is Record<T> (semantically) the same as {[ key: string ]: T | undefined } PS: Record<T> (语义上)是否与{[ key: string ]: T | undefined }相同? {[ key: string ]: T | undefined } ? {[ key: string ]: T | undefined } ?

UPDATE FOR TYPESCRIPT 4.1+打字稿 4.1+ 的更新

There is now a --noUncheckedIndexedAccess compiler option which, when enabled, includes undefined when reading from index signature properties.现在有一个--noUncheckedIndexedAccess编译器选项,启用后,从索引签名属性读取时包括undefined This option is not part of the --strict suite of compiler options, because it's too much of a breaking change and some of the workarounds are annoying.此选项不是编译器选项--strict套件的一部分,因为它的破坏性变化太大,而且一些变通方法很烦人。


PRE-TS4.1 ANSWER: PRE-TS4.1 答案:

This has been raised as a suggestion (see microsoft/TypeScript#13778 ) and has essentially been declined (although it is listed as "awaiting more feedback") because it is expected to cause more bugs than it would fix.这是作为建议提出的(参见microsoft/TypeScript#13778 )并且基本上已被拒绝(尽管它被列为“等待更多反馈”),因为预计它会导致比修复更多的错误。 You're right that the current situation is inconsistent and technically incorrect/unsound, but it is not one of TypeScript's goals to "apply a sound or 'provably correct' type system. Instead, [it should] strike a balance between correctness and productivity."您说得对,当前情况不一致且技术上不正确/不健全,但TypeScript 的目标之一不是“应用健全或‘可证明正确’的类型系统。相反,[它应该] 在正确性和生产力之间取得平衡。”

TypeScript doesn't actually enforce every possible key matching the index to be present (so index signature properties are effectively optional), but it does enforce that any such key which is present has a defined value of the right type... this is one of the few places in TypeScript where missing and undefined are distinguished . TypeScript 实际上并没有强制每个与索引匹配的可能键都存在(因此索引签名属性实际上是可选的),但它确实强制存在的任何此类键具有正确类型的定义值......这是一个在 TypeScript 中区分缺失和未定义的少数几个地方。

As you noted, if you want your own index-signature types to behave the same as other optional properties (meaning that undefined is automatically a possible value), you can add | undefined正如您所指出的,如果您希望自己的索引签名类型的行为与其他可选属性相同(这意味着undefined自动成为可能的值),您可以添加| undefined | undefined to the property type. | undefined到属性类型。 If you want existing index-signature types to behave this way (like Array ), you'll have to fork your own copy of the standard library and do it for yourself .如果您希望现有的索引签名类型以这种方式运行(如Array ),您将不得不派生出您自己的标准库副本并自己完成 They won't do it upstream because it would make lots of people very sad to deal with this .他们不会在上游这样做,因为这会让很多人非常难过

If you really want to see this changed, you might want to visit the GitHub issue and comment or upvote, but I wouldn't hold my breath... your time is probably better spent moving past this (I speak from experience... I've had to do this several times when dealing with TypeScript's pragmatic inconsistencies.)如果你真的想看到这种变化,你可能想访问 GitHub 问题并发表评论或投票,但我不会屏住呼吸......你的时间可能最好花在过去(我从经验中讲......在处理 TypeScript 的语用不一致时,我不得不多次这样做。)

I hope that helps.我希望这会有所帮助。 Good luck!祝你好运!

This is just an addition to the accepted answer, because it's totally right这只是对已接受答案的补充,因为它完全正确

If your aim is to get compile time errors if you don't check if eg sales.d exists/is not undefined , you could implement your own interface here:如果您的目标是在不检查例如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 there is no such built-in interface in typescript. AFAIK 打字稿中没有这样的内置接口。

I think index signatures (in your case) make sense if you want to iterate over the keys of an such an object:如果您想遍历这样一个对象的键,我认为索引签名(在您的情况下)是有意义的:

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];
}

I assume there are much more uses cases which are not coming into my mind right now..我认为现在还有更多的用例没有出现在我的脑海中。

To your side question: No, it's not (if you meant Record from here . Record<T> does not even compile, because it needs a second type argument. I would say Record 's are not really related to your issue.对于您的问题:不,不是(如果您的意思是Record from hereRecord<T>甚至无法编译,因为它需要第二种类型的参数。我会说Record与您的问题并不真正相关。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM