【问题标题】:Coercing type with optional properties to an indexable type将具有可选属性的类型强制为可索引类型
【发布时间】:2021-02-06 20:06:24
【问题描述】:

Typescript 在尝试将具有可选属性的类型作为可索引类型传递时抛出错误:(Playground)

type Thing = {
    thing1?: string
    thing2?: string
    thing3?: number
}

const thing: Thing = {}

function processObject (obj: { [key: string]: string | number }): string {
    /* Generic object handler, not specifically for Thing */
    return "test"
}

console.assert(processObject(thing) === "test")

这会导致:

错误:'Thing' 类型的参数不可分配给'{ [key: string]: string | 类型的参数数字; }'。属性“thing1”与索引签名不兼容。键入'字符串 | undefined' 不可分配给类型 'string |数字'。类型“未定义”不可分配给类型“字符串 |号”。

当然,如果参数的类型被强制设为可选,它会起作用:

function processObject (obj: { [key: string]: string | number | undefined }): string {
    return "test"
}

不过,我不明白为什么这是必要的。根据TS PR #7029,可索引类型应该与具有相同隐式索引签名的其他类型兼容。

这些属性是否是可选的无关紧要-该属性根本不应该出现在对象上-对吗?为什么我必须指定undefined?有没有更好的方法来做到这一点?

【问题讨论】:

    标签: typescript


    【解决方案1】:
    【解决方案2】:

    考虑到根据您对Thing 的定义,以下行将在没有警告的情况下编译:

    const A: Thing = { thing2: undefined };
    

    这会在调用processObject() 时出错技术上正确;当您只期望 stringnumber 时,您最终可能会从对象中读取 undefined 值。


    解释:

    TypeScript 并不总是区分值(如对象属性或函数参数)缺失的情况与值存在但undefined的情况。这种混淆是从 JavaScript 继承而来的,其中的区别可能很微妙:如果我有一个名为 obj 的 JavaScript 对象,而 obj.prop === undefinedtrue,我无法判断 "prop" in obj 是真还是假。

    GitHub 中有一个长期未解决的问题,microsoft/TypeScript#13195,要求在区分 TypeScript 中的“缺失”和 undefined 方面保持一致。可选属性被视为“可能丢失”和“可能undefined”,而相反,在其定义中带有| undefined 的必需属性不允许丢失。现在没有办法说“我想要一个可能丢失的属性,但如果它存在,它不应该undefined”。

    此外,index signatures 也遭受了相反方向的双重思考:实际上,您可以从中获取 undefined 属性值(因为任何给定的属性都可能丢失)但编译器不承认这一点(并且表现得像每个可能的属性都存在并定义)。请参阅microsoft/TypeScript#13778 以了解将undefined 自动包含在索引签名属性域中的建议,以及有关它的无数 cmets。即将推出一个名为--noUncheckedIndexedAccess(参见microsoft/TypeScript#39560)的功能标志,旨在解决这个问题,但即使您打开它,您的代码仍然会遇到同样的问题,因此它并不能在所有情况下都完全修复它.

    缺失值和undefined 值在可选属性中的处理方式与它们在索引签名中的处理方式之间的不匹配是导致问题的原因。


    在我看来,处理这个问题的方法就是将undefined 添加到您的索引签名中,并明确承认可能存在可选属性但undefined。这并不理想,但至少更接近一致。


    Playground link to code

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-04
      • 2011-01-06
      • 1970-01-01
      相关资源
      最近更新 更多