【问题标题】:Property 'foo' does not exist on type '{}' when using new Proxy({}), .....)使用新代理({})时,类型“{}”上不存在属性“foo”,.....)
【发布时间】:2022-01-04 20:46:08
【问题描述】:

我没有使用 typescript(而且,现在我不打算使用),但是 VSCode 的默认设置似乎已经为我做了一些检查。这有点方便,有点痛苦。我现在想坚持下去。

导致此问题的代码是:

  let {
    localApiVersion, localDate, remoteVersion, remoteDate,
  } = new Proxy({}, { get: () => null });

我从我的answer here 中获取的。我这样做是因为我不想做四次let localApiVersion = null

但是 VSCode 给了我这个错误:

类型“{}”.ts(2339) 上不存在属性“localApiVersion”

检查(我认为)是因为我的jscongig.json 看起来像这样:

{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es2019",
        "checkJs": true
    },
    "exclude": [
        "node_modules",
        "**/node_modules/*"
    ]
}

我知道我可以在该行上方写// @ts-ignore,但不想养成这种习惯。

有没有办法,不删除检查(或在项目中添加打字稿),通知 VSCode 这些都可以?

【问题讨论】:

  • 尝试给{} 一个类型注释,它确实有一个foo 属性?
  • 您在 JavaScript 代码上遇到 TypeScript 错误似乎很令人惊讶。您拥有此代码的文件的完整文件名是什么?
  • @T.J.Crowder 'resources.js'
  • @Pureferret 我不够熟悉,无法提供具体信息,抱歉????

标签: javascript visual-studio-code static-analysis


【解决方案1】:

{} 类型来自ProxyConstructor 中的T extends object 约束;在没有显式类型的情况下,T 被解析为一个空对象,或者{}

但是,{} 不符合要求,因为它没有任何属性,而您的代码要求它具有 localApiVersionlocalDate 等。是的,JavaScript 知道这些属性(或者更确切地说它不关心),但 TypeScript 不知道它们,它无法与运行时代码通信。

解决方案是至少对这张图片中的某些内容进行类型转换,以便 TypeScript 可以推断出正确的类型。在.ts 文件中,这是微不足道的。但是,在.js 文件中,可以这样做:

// @ts-check

/** @type {Record<string, unknown>} */
const target = {};

let { foo, bar, baz } = new Proxy(target, { get: () => null });

【讨论】:

  • 未知是一回事吗?我根据你和 TJ 的回答得到了这个工作:let { localApiVersion, localDate, remoteVersion, remoteDate} = /** @type {Object.&lt;string, null&gt;} */ (new Proxy({}, { get: () =&gt; null }));
  • 在我看来,如果他们打算使用Record&lt;string, unknown&gt;,他们还不如完全关闭类型检查。你知道一种方法来做一个相当于the TypeScript version 的JSDoc 吗? (我在那里用过any,但可能是unknown。)
  • @T.J.Crowder 有,在 JSDoc 领域我们称之为typedef
  • @Pureferret - 我试过了,但没有让它以任何有用的方式工作。 (您可以将它用于Record&lt;string, unknown&gt; 等,但没有意义。)您是否让它以有用的方式工作?
  • @T.J.Crowder 对我有用。我将其添加为单独的答案。
【解决方案2】:

您在 JavaScript 代码上遇到 TypeScript 错误似乎很令人惊讶,但您可以通过 JSDoc 注释提供类型信息(请参阅 hereherehere),它们只是 cmets,因此它们不会'在 JavaScript 环境中运行代码之前不需要使用 TypeScript 编译器。

话虽如此,但我无法让它与 JSDoc 注释一起使用。我希望这会起作用,因为third link above 说您可以通过这种方式进行类型断言:

// @ts-check

/**
 * @typedef {Object} Stuff - comment here
 * @property {any} localApiVersion - comment here
 * @property {any} localDate - comment here
 * @property {any} remoteVersion - comment here
 * @property {any} remoteDate - comment here
 */

let {
    localApiVersion, localDate, remoteVersion, remoteDate,
} = new Proxy(/** @type {Stuff} */ {}, { get: () => null });;

但这不起作用。 :-(

就其价值而言,这在 TypeScript 本身中很容易:

interface Stuff {
    localApiVersion: any;
    localDate: any;
    remoteVersion: any;
    remoteDate: any;
}

let {
    localApiVersion, localDate, remoteVersion, remoteDate,
} = new Proxy({} as Stuff, { get: () => null });
//               ^^^^^^^^−−−−−−− type assertion
// I normally avoid type assertions, but this use of the Proxy with get
// trap is a very special case.

TypeScript playground 上的示例。)

我希望 JSDoc 注释可以实现,因为我知道人们使用 TypeScript 类型检查的方式,但是,我只是使用 TypeScript 并且无法找出 JSDoc 等价物。

【讨论】:

  • 这些是有用的链接!我快速浏览了一下 (specifically this),然后添加说 /** @type {{localApiVersion: null, localDate: null, remoteVersion: null, remoteDate: null}} */ 是 a) 我试图避免的那种冗长,并且 b) 似乎不起作用?
  • 例如,它要么什么都不做,要么给我这个Type '{}' is missing the following properties from type '{ localApiVersion: null; localDate: null; remoteVersion: null; remoteDate: null; }': localApiVersion, localDate, remoteVersion, remoteDate ts(2739)
  • 是的,我一直在尝试如何通过这种机制进行类型断言,但我无法让它工作。我可以分配一个类型,但是尽管this 说你可以内联进行类型断言,但我无法让它工作。 :-(
  • 这有助于关闭错误:let { localApiVersion, localDate, remoteVersion, remoteDate, } = /** @type {Object.&lt;string, null&gt;} */ (new Proxy({}, { get: () =&gt; null })); 并且 VSCode 也告诉我它们的 null
  • @Pureferret - 这将消除错误,但不会提供任何有用的东西。你也可以关闭类型检查。
【解决方案3】:

这对我有用(请也为其他答案投票,它们对我到达这里很有帮助):

  let {
    localApiVersion, localDate, remoteVersion, remoteDate,
  } = /** @type {Object.<string, (null|string)>} */ (new Proxy({}, { get: () => null }));

请注意@type 注释位于new 之前,并且整个构造函数部分都包含在括号中。我使用(null|string) 而不是unknown a) 因为我知道它将被重新分配给一个字符串和b) 所以我仍然得到一些 类型检查,即使在重新分配你之前可能会出现类型错误。我可以将其切换为 null,并且在更改类型时明确使用这种东西:@type {string} (localApiVersion)

这是 VSCode 中的工具提示:

使用typedef 也可以:

  /**
   * @typedef {Object.<string, (null|string)>} InitProxy
   */

  let {
    localApiVersion, localDate, remoteVersion, remoteDate,
  } = /** @type {InitProxy} */ (new Proxy({}, { get: () => null }));

但这已经达到了我试图避免的冗长程度。

【讨论】:

  • null | string 表示该值为null 或字符串。你怎么知道它可以是一个字符串?
  • 因为稍后我将它重新分配给一个字符串
  • 哦,你是 OP :) 错过了 :)
  • 如果你在.js 文件中编写,并且jsconfig.json 中没有strictNullCheck 编译器选项,那么你不需要null | string,因为strictNullCheck 是默认关闭,-string 就足够了
  • @DimaParzhitsky 很高兴知道
猜你喜欢
  • 2021-08-08
  • 2017-09-01
  • 2012-12-06
相关资源
最近更新 更多