【问题标题】:TypeScript assumes that literally any key is guaranteed to exist on a RecordTypeScript 假定任何键都保证存在于 Record 中
【发布时间】:2022-11-19 01:52:57
【问题描述】:

这是一些代码:

declare const foo: Record<string, number>

const x = foo['some-key']

TypeScript 说 x 的类型是 number

应该number | undefined,因为不能保证对象上存在some-key

为什么即使使用strict: true,TypeScript 是否也给出了这种错误的保证?

【问题讨论】:

    标签: typescript


    【解决方案1】:

    您可以使用 noUncheckedIndexedAccess 属性(“使用索引访问时将未定义添加到类型。”)启用此行为,请参阅this playground

    至于为什么那不是strict 行为,我只能猜测:它模仿默认配置中数组的行为。本质上,数组(至少在访问其元素方面)可以理解为 Record&lt;int, T&gt;。在通常情况下,您知道哪些元素存在并且您可以访问,并且 TypeScript 相信您会正确地这样做(也许是愚蠢的)。

    实际上,我从来没有想过 Record&lt;string, number&gt; 在索引访问时不会返回 number | undefined,因为那是我告诉它的。 string进,number出。我可以看到你来自哪里!

    不过,更明确的答案可能需要决策者之一或活跃的 TypeScript 维护者来确定。

    【讨论】:

    • 如果这是默认行为,那就更烦人了……想象一下必须在任何地方使用!,或者每次你想访问一个元素时都要缩小!
    【解决方案2】:

    应该number | undefined,因为不能保证对象上存在某个键。

    我不认为这通常是正确的。我倾向于避免可选字段,并且使用一个比 { [K in MyKeys]: number } 可读性更高的实用程序来创建详尽的对象类型是非常好的。

    没有什么能阻止您写 Partial&lt;Record&lt;string, number&gt;&gt; 或创建您自己的 PartialRecord

    type PartialRecord<K extends PropertyKey, T> = { [P in K]?: T }
    

    我会将 Record 视为类型级宏,仅此而已。它没有哲学意义。

    你写的完全等同于写一个简单的索引签名。这不是Record真正闪耀的地方。以下类型完全相同:

    type foo = Record<string, number>;
    type foo = { [K in string]: number };
    type foo = { [k: string]: number };
    

    Record 当你已经有一些联合类型并且你想从它创建一个对象类型时更有用:

    type MyKeys = 'foo' | 'bar' | 'baz';
    
    type foobar = Record<MyKeys, number>
    
    // same as
    type foobar = {
        foo: number
        bar: number
        baz: number
    };
    

    TS 不是一个健全的类型系统。试图理解它只会令人沮丧。如果您将其视为丑陋的 Javascript 的丑陋类型级编程语言,您会更快乐;)

    【讨论】:

      猜你喜欢
      • 2019-04-16
      • 2012-09-08
      • 1970-01-01
      • 2010-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多