【问题标题】:Extending Vue instance interface in TypeScript Quasar boot file在 TypeScript Quasar 启动文件中扩展 Vue 实例接口
【发布时间】:2021-01-24 15:01:47
【问题描述】:

编辑:我在下面的帖子中多次说过我“不在模块中”。任何时候一个文件中的 JavaScript 代码从另一个技术上是一个模块的文件中调用。我的意思是这个模块是由 Quasar 在脚本初始化时自动调用的,预计会产生全局副作用。该模块永远不会导入到我编写的任何代码中。

简洁的帖子:

我正在使用带有 TypeScript 支持和 Vue 类组件的 Quasar 2.0.0。我希望在我的类中添加一个可访问的实例属性:this.$fetch(...);

我创建了一个包含以下内容的启动文件:

import Vue from "vue";

declare module "vue/types/vue"
{
    interface Vue
    {
        prototype: {
            $fetch: (resource: (string | Request), init?: RequestInit) => Promise<Response>
        },
        $fetch: (resource: (string | Request), init?: RequestInit) => Promise<Response>
    }
}

type Context = {
    Vue: Vue
};

export default async ({ Vue: vue }:Context) =>
{
    vue.prototype.$fetch = async (resource, init) =>
    {
        return fetch(resource, init);
    };
};

这不会引发任何 TypeScript 错误。但是当我尝试在组件中使用它时,我得到一个错误:

<template>
    <q-layout>
        <q-page-container>
            <q-page class="flex flex-center">
                <h1>Test</h1>
            </q-page>
        </q-page-container>
    </q-layout>
</template>

<script lang="ts">
import { Vue, Component } from "vue-property-decorator";

@Component
export default class TestPage extends Vue
{
    mounted ()
    {
        this.$fetch("https://www.google.com");
    }
}
</script>

类型“TestPage”上不存在属性“$fetch”。

上一篇(杂乱无章)的帖子:

我正在开发 Quasar 应用程序,为了方便起见,我想创建一个修改后的 fetch 方法,如果请求的域与我的后端域匹配,则该方法会注入我的 API 密钥。界面类似于:

@Component
export default class VueComponent extends Vue
{
    mounted()
    {
        this.$fetch("https://www.example.com/api/endpoint").then(console.log);
    }
}

我知道如何定义这样的东西。我只需要根据https://vuejs.org/v2/cookbook/adding-instance-properties.html 更新Vue 原型:

Vue.prototype.$fetch = async function(request, init)
{
    // ... blah ...
};

根据Quasar's documentation,更新 V​​ue 原型的适当时间在 引导文件 中。所以我创建了一个:

quasar new boot fetch

我的启动文件开始时相当简单:

export default async ({ Vue }) =>
{
    Vue.prototype.$fetch = async (resource, init) =>
    {
        return fetch(resource, init);
    };
};

当我尝试转换为 TypeScript 时,一切都崩溃了。参数Vue 隐式具有any 类型,因为没有为参数对象提供类型。

我尝试像这样定义类型:

import Vue from "vue";

type Context = {
    Vue: Vue
};

export default async ({ Vue }:Context) =>

然而,这引起了关于变量阴影的抱怨(Vue 定义在上层范围内)。我注意到Vue 变量的类型是VueConstructor&lt;Vue&gt;,所以我改为尝试:

import { VueConstructor } from "vue";

type Context = {
    Vue: VueConstructor
};

export default async ({ Vue }:Context) =>

这适用于函数定义,但在 Vue.prototype.$fetch = ... 行上引发错误:“不安全的成员访问 .$fetch 对任何值”。 TypeScript 不希望 Vue.prototype 具有 $fetch 属性。如果我要进行模块定义,我会像这样扩展接口:

declare module "abc" {
    VueConstructor: {
        prototype: {
            $fetch: ...
        }
    }
}

但是我没有声明一个模块——这是一个引导文件。我尝试了一个快速破解来解决这个问题,只在我的引导文件的上下文中定义我自己的VueConstructor

interface VueConstructor
{
    prototype: {
        $fetch: (resource: (string | Request), init?: RequestInit) => Promise<Response>
    }
}

type Context = {
    Vue: VueConstructor
};

export default async ({ Vue }:Context) =>
{
    Vue.prototype.$fetch = async (resource: (string | Request), init?: RequestInit) =>
    {
        return fetch(resource, init);
    };
};

这终于让 TypeScript 停止抱怨 this 文件,但是当我尝试在组件中使用 this.$fetch 时:

“VueComponent”类型上不存在属性“$fetch”。

由于VueComponent 扩展Vue 我想我需要更新Vue 类的定义,但我不知道如何做到这一点。我尝试将以下内容添加到我的启动文件中:

interface Vue
{
    $fetch: (resource: (string | Request), init?: RequestInit) => Promise<Response>
}

但这没有用。我不能只使用declare module,因为我不在模块中。如何在没有模块的情况下全局扩展类型?

【问题讨论】:

  • 阴影完全有效,但可以使用标准参数或内联重命名。请不要将您的个人风格规则与 TypeScript 错误混为一谈。
  • @AluanHaddad 这很公平,尽管即使解决了Vue 的问题(与VueConstructor 相比)我不确定如何全局更新Vue 接口,以便其他脚本会注意到我添加的新属性
  • 将您的最后一个 sn-p 包装在 declare module "vue" {} 中。通过在顶层添加 export {} 使其成为一个模块,如果你不在一个模块中
  • @AluanHaddad 刚刚尝试了一下,但没有解决。这个问题可能与 Quasar 对基于类的组件的使用有关。我正在创建的VueComponent 实际上并没有导入“vue”,而是导入了“vue-property-decorator”(import { Vue, Component } from "vue-property-decorator";)。我尝试使用declare module "vue-property-decorator" 而不是declare module "vue",但这给出了“vue-property-decorator”不存在的错误?

标签: javascript typescript vue.js quasar-framework


【解决方案1】:

我的“简洁文章”中的代码示例(显示了我在反复试验后得出的结果)实际上可以工作——我只需要重新启动计算机(可能只需要重新启动我的 IDE,但没有完全关闭出于某种原因将其关闭)

【讨论】:

    猜你喜欢
    • 2016-07-06
    • 2021-01-30
    • 1970-01-01
    • 1970-01-01
    • 2020-10-30
    • 2020-06-09
    • 2017-10-21
    • 2020-04-09
    • 2018-06-20
    相关资源
    最近更新 更多