【问题标题】:Declaring object property type in function param在函数参数中声明对象属性类型
【发布时间】:2021-09-03 12:54:11
【问题描述】:

这个问题让我很困惑,我什至不知道如何正确命名这个问题。

几个小时前我开始学习 TypeScript,但遇到了 Property 'whatever' does not exist on type 'object'. 智能感知错误。

我觉得我应该为这个对象声明一个定义相关属性的接口,但感觉不对,因为该对象是一个事件侦听器参数,所以我不直接调用该函数 -我正在使用的图书馆确实如此。它也感觉像一个我只会使用一次的东西的界面是多余的。

让我告诉你我的意思:

// this event listener is created by the library I'm using, so I can't change the params it sends
this.load.on('fileprogress', (file: object) => {
  console.log(`Loading asset: ${file.key}`); // ".key" is crapping out with "Property 'key' does not exist on type 'object'."
});

最简单的解决方案似乎只是使用(file) => {...},以便默认输入any,但我想避免这种情况,否则我还不如回到使用普通的旧JavaScript。我想出的下一件事是在事件侦听器上方声明interface File { key: string },然后将函数更改为(file: File) => {...},但这感觉像是一种黑客行为,因为就像我说的那样,我不是调用这个函数的人并且有零控制实际上作为参数发送的内容。此外,整个interface File... 感觉过于冗长。

我在想,沿着接口线,是不是有一些方法可以在参数列表中内联声明属性的类型。像(file: object { key: string }) 这样的东西?如果我们从字面上看它是一个内联接口,这仍然是一个 hack,但至少我们现在告诉它该对象应该具有哪些属性,对吧?

我想出的一个不会引发智能感知错误的事情是这个怪物 (file: {[key: string]: any} = {}) => {},但又是一个可怕的 any 关键字,智能感知将其报告为......好吧,我不甚至知道它应该是什么。这是截图。

我想我要问的底线问题是处理这种情况的正确方法是什么,您不直接调用的函数需要接收具有您无法预测的属性的对象,因此可以'不定义?

【问题讨论】:

    标签: javascript typescript types


    【解决方案1】:

    惯用的 TypeScript 类型是 Record<string, unknown>。这假设您将收到一个带有字符串属性名称的对象,但不假设特​​定属性名称或它们的值可能具有的类型。然后,您将需要执行运行时narrowing 测试,以便安全地访问该对象的任何属性。所以,例如:

    this.load.on('fileprogress', (file: Record<string, unknown>) => {
        if (typeof file.key === 'string') {
            console.log(`Loading asset: ${file.key}`);
        }
    });
    

    (注意这里的typeof守卫不必简单说.key,因为Record对象将允许任何字符串属性名称。需要确认该值的存在并键入[我猜@987654327 @])。

    但是,您确定您使用的库完全没有表示它传递给您的对象的形状吗?即使对于一个普通的 JS 库,这似乎也不寻常。许多(如果不是大多数)库现在甚至都有自己的 TypeScript 类型(直接或通过 @types/* 包),使这些参数类型隐含。

    【讨论】:

    • 我什至不知道用什么词来表达我的问题,然后你过来为我解决了整个问题,非常感谢!关于您的最后一个问题 - 我实际上不确定库 真的 是否没有表示对象的形状 - 它可能在 node_modules 的某个地方。但我不确定我是否想在那里编辑界面。话虽如此,我还是真的不知道我在说什么,所以如果你在这方面有更多的建议,或者知道这种情况应该如何处理,我会很高兴听到它。
    • 无需编辑库的代码。您可以尝试将@types/[library-package-name] 安装为--dev 依赖项;如果可行,file arg 的类型应该是隐式的,您根本不必指定它。如果没有,您应该能够查阅库的文档并基于此定义参数类型。例如,如果 file 参数是具有一个属性 key 的对象,则您可以说 (file: { key: string }),其值为 string
    猜你喜欢
    • 2017-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-16
    • 1970-01-01
    • 1970-01-01
    • 2012-02-16
    相关资源
    最近更新 更多