【问题标题】:How do I add a property to an array type?如何将属性添加到数组类型?
【发布时间】:2018-09-06 02:53:15
【问题描述】:

在 Vue 中,我们有这种类型:

Vue.$refs: {
    [key: string]: Vue | Element | Vue[] | Element[];
}

我有一个第三方库 (vuelidate),它为所有 Vue.js 添加了 $v 属性。它没有定义类型,所以我自己做。

declare module 'vue/types/vue' {
  interface Vue {
    $v: any
  }

  interface Element {
    $v: any
  }
}

当我尝试像这样在 $refs 上使用 $v 时,打字稿会抱怨:

this.$refs.form.$v

结果

Property '$v' does not exist on type 'Vue[]'.

这对我来说很有意义。但是,没有意义的是如何向 Vue[]Element[] 添加属性以便编译此代码。


我已经翻阅了文档 Stack Overflow,您可以命名它,但我找不到解决此问题的方法。如何将类型添加到特定数组?

我明白为什么这不起作用:

interface Vue[] {
  $v: any
}

但我不知道如何解决它。

【问题讨论】:

  • 数组必须用数字键访问;例如,您必须使用this.$refs.form[0].$v
  • @ExplosionPills 这个想法不错,但是联合类型是Vue | Element | Vue[] | Element[],这意味着一些潜在类型没有索引签名。
  • 在这种情况下,我认为您将不得不转换为您当时需要的类型
  • 是的,我也猜你将不得不使用(this.$refs.form as Vue).$v
  • 谢谢,成功了。我肯定是想多了这个问题!

标签: typescript


【解决方案1】:

强制转换有效,但我很欣赏您声明类型的愿望,这样您就不必每次都强制转换。 Vue[] 实际上是Array<Vue> 的简写,是内置泛型接口Array 的参数化。您可以将属性添加到Array,但随后它们将在所有类型的数组上声明,而不仅仅是Vue[]。您可以使用条件类型来缓解这种情况,如下所示:

// Wrap with `declare global { ... }` if the file is an ES6 module
interface Array<T> {
    $v: T extends Vue | Element ? any : unknown;
}

但实际上,您不希望每个Vue[] 上都有$v,而只希望Vue.$refs 上。不幸的是,考虑到Vue.$refs 的声明方式,我不相信有任何方法可以通过扩充来进行这种更改。您必须将 vue 包的修改版本添加到您的项目中,并将声明更改为:

export interface Vue {
  // ...
  readonly $refs: { [key: string]: (Vue | Element | Vue[] | Element[]) & {$v: any} };
  // ...
}

显然,此更改不适合向上游发送。但是你可以发送一个 PR 来添加一个钩子,这样其他包(例如 vuelidate)就可以增强:

// In vue/types/vue.d.ts:
export interface RefExtra {}
export interface Vue {
  // ...
  readonly $refs: { [key: string]: (Vue | Element | Vue[] | Element[]) & RefExtra };
  // ...
}

// In vuelidate typings (or your project for now):
declare module 'vue/types/vue' {
  interface RefExtra {
    $v: any
  }
}

【讨论】:

  • 很棒的答案,谢谢。我想知道它应该如何工作的一切。
猜你喜欢
  • 2018-08-22
  • 2017-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-27
  • 2018-09-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多