【问题标题】:Typed object literal with nested properties can't get intellisense to work具有嵌套属性的类型化对象文字无法使智能感知工作
【发布时间】:2020-08-17 17:14:29
【问题描述】:

我正在尝试使用 typescript 改进我的一个项目,但我不知道如何使以下内容起作用。

说我有这么简单的函数表达式

const foo = (objectLiteral: any): void => {
  console.log(objectLiteral)
}

现在,我就这样使用它。

foo({
  name: 'guybrush',
  nestedProperties: {
    gunPowderAmount: 1
  },
  speak () {
    // First issue, "this" is any type. I don't get any intellisense for the properties 
    // within the object.
    // this.
  }
})

根据我在 speak 函数中的评论,“this”具有任何类型,我无法访问该对象的任何属性。我相信这与https://github.com/microsoft/TypeScript/issues/11072 有关。

我知道这与打字稿无关——但是——我已经到了。

然后我假设,因为我使用的是 typescript,所以我可以利用类型,太棒了! 所以我的代码变成了以下内容:

type MappedCharacter = {
  name: string;
  speak: () => void;
  nestedProperties: { [key: string]: number | string };
}

const foo2 = (objectLiteral: MappedCharacter) => {
  console.log(objectLiteral)
}

我会这样使用它:

foo2({
  name: 'guybrush',
  nestedProperties: {
    gunPowderAmount: 1
  },
  speak () {
    // Second issue. Now "this" has access to the properties, but NOT
    // the one which are NESTED into "nestedProperties"
  }
})

酷,我现在可以访问“this”,并且可以定位属性“name”和“nestedProperties”。

但是,嘿,“nestedProperties”还有其他属性!他们在哪里?

最终测试,我要去掉函数表达式,自己测试对象。

const objectLiteral: MappedCharacter = {
  name: 'guybrush',
  nestedProperties: {
    gunPowderAmount: 1
  },
  speak () {
    // Third issue. Even if not used in a function, "this.nestedProperties" can't dig any 
    // deeper.
    // this.nestedProperties.
  }
}

从 speak 函数中的评论来看,再一次,我没有运气使嵌套属性工作。

我也尝试过没有运气,将我的类型更改为:

type MappedCharacter = {
  name: string;
  speak: () => void;
  nestedProperties: keyof MappedCharacter['nestedProperties'];
}


'nestedProperties' 的结果在其自己的类型注释中被直接或间接引用

编辑: 我不想为“nestedProperties”对象定义一个类型。 我只是希望它尽可能通用,因为我无法预见它可以拥有什么样的属性。

编辑2: 如果我有一个普通的对象文字,没有任何类型,vscode 可以确定这些属性,尽可能嵌套。我想用类型实现相同的行为。 我通常在我的项目中使用 Vuejs,带有 Vetur 扩展,当我为我的数据函数定义不同的属性时,智能感知就可以工作了。

谁能解释一下这个问题? 谜题中缺少什么?

【问题讨论】:

  • 也许你应该为嵌套属性添加一个更好的接口。我的意思是,你正在使用一个通用接口,它说有一个未知的密钥,所以对于智能感知,密钥是未知的。它只知道它是一个字符串。
  • 但这正是我想要的。 “nestedProperties”可以有不同的属性,我不想预先定义。因此是通用接口。
  • 这就是问题所在,IntelliSense 怎么可能知道nestedProperties 的属性是什么?它可以是运行时任何有意义的字符串,因此它不知道那里的属性是什么。
  • 您能否更详细地解释一下,作为“正确结果”,您究竟希望在这里发生什么?你想在speak()函数体中输入this.nestedProperties,然后IntelliSense调出gunPowderAmount的建议吗?
  • 我希望智能感知能够调出“nestedProperties”拥有的任何属性。我会更新我的问题。

标签: typescript visual-studio-code javascript-objects intellisense


【解决方案1】:

当你定义你的MappedCharacter 类型时,你基本上说nestedProperties一些 属性。你没有定义哪个,所以编译器没有这个信息。

然后,您创建 objectLiteral 对象,其中 nestedProperties 具有 gunPowderAmount 属性 - 但它仅适用于这个特定的对象,并且在那个特定的时刻。 speak() 函数仍然针对 MappedCharacter 类型进行类型检查,该类型仍然没有在任何地方定义 gunPowderAmount 属性。

我建议,如果您知道 MappedCharacter 有哪些不同的属性,请改为这样定义:

type MappedCharacter<TProps> = {
  name: string;
  speak: () => void;
  nestedProperties: TProps
}

type GuybrushProps = {
  gunPowderAmount: number
}

const objectLiteral: MappedCharacter<GuybrushProps> = {
  name: 'guybrush',
  nestedProperties: {
    gunPowderAmount: 1
  },
  speak () {
    // Then, intellisense here should work as you expect it to
  }
}

【讨论】:

  • 嗨,在我指定的问题中:另外,我不想在“nestedProperties”对象中定义属性。我只是希望它尽可能通用,因为我无法预见它可以拥有什么样的属性。抱歉,如果不清楚。
  • 如果你不能预见它可以拥有什么样的属性,那么编译器也不能,你也不会得到关于这些属性的任何建议。
  • 好的,但是,如果我有一个普通的对象文字,没有任何类型,vscode 可以确定这些属性,尽可能嵌套。如果这是可能的,为什么打字不是这样?另外,我通常在我的项目中使用 vuejs,带有“Vetur”插件,我不知道你是否熟悉它们,虽然,当我为我的数据函数定义不同的属性时,智能感知就可以工作了。此刻这让我很烦。
  • 当你有一个带有键的对象文字时,IntelliSense 使用你已经在文字中定义的键。这就是这里的区别。
  • 绝对没有办法用类型复制它? @EugeneObrezkov
猜你喜欢
  • 1970-01-01
  • 2016-11-07
  • 1970-01-01
  • 1970-01-01
  • 2016-10-26
  • 1970-01-01
  • 2020-10-24
  • 1970-01-01
相关资源
最近更新 更多