首页 > 解决方案 > 如何创建具有可选值的接口

问题描述

我有一个对象,一开始我不知道其中会有什么键,但打字稿似乎没有考虑键的值可能不存在的可能性:

interface ById {
    [key:string]: number[]
}

const test: ById = {
    dummyValue: [1,2,3]
}

const doThing = (key: string) => {
    // regardless of if this key exists, it still assumes it's an array
    test[key].push(4)
}

doThing('test')

我想我会创建一个接口,明确表明该项目的值可能未定义,因此如果我不检查它是否存在,它会显示错误,但由于某种原因,它会显示错误,即使我检查

interface ByIdOptional {
    [key:string]: number[] | undefined
}

const test: ByIdOptional = {
    dummyValue: [1,2,3]
}

const doThing = (key: string) => {
    if (typeof test[key] !== 'undefined') {
        // Even though I'm testing for undefined, it's showing an error here
        test[key].push(4)
    }
}

doThing('test')

有没有更好的方法来实现这一点,并获得使用该对象的类型安全代码?我也将代码添加到了 Typescript Playground(用于测试)

标签: typescript

解决方案


| undefined的索引签名值类型是个好主意;现在,令人难以置信的假设索引签名类型在每个键上都有定义的值。undefined编译器总是期望索引签名中的可能值更正确但可能令人讨厌。有一个开放的 GitHub 问题跟踪此问题(microsoft/TypeScript#13778),但我预计不会很快发生任何变化。

您检查的问题是编译器实际上没有办法跟踪typeof test[key] !== 'undefined'. 该变量key只知道是类型string。编译器可以做的唯一可能的缩小范围是说“所有string值的键test都已被验证不是undefined”。这不是一个理想的缩小范围,所以编译器基本上什么都不做。有一个关于此的 GitHub 问题文件 ( microsoft/TypeScript#31445 ),该文件作为设计限制已关闭。为了解决这个问题,语言必须跟踪哪些单独的变量被用作类型保护中的键,这对于它偶尔提供的帮助来说是很多额外的工作。

这里最简单的解决方法是将有问题的值复制到一个新变量中,可以通过控制流分析进行检查,而不必担心重新进行属性访问:

const doThing = (key: string) => {
    const testKey = test[key];
    if (typeof testKey !== 'undefined') {
        testKey.push(4)
    }
}

好的,希望有帮助;祝你好运!

Playground 代码链接


推荐阅读