Расширение интерфейса экземпляра Vue в загрузочном файле TypeScript Quasar

Изменить: в сообщении ниже я несколько раз сказал, что я не участвую в модуле. Каждый раз, когда код JavaScript в одном файле вызывается из другого, технически являющегося модулем. Я хотел сказать, что этот модуль автоматически вызывается Quasar во время инициализации скрипта и, как ожидается, будет иметь глобальные побочные эффекты. Модуль никогда не импортируется ни в какой код, который я пишу.

Краткое сообщение:

Я использую Quasar 2.0.0 с поддержкой TypeScript и компонентами класса Vue. Я хочу добавить свойство экземпляра, которое будет доступно в моих классах как: 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>

Свойство $ fetch не существует для типа TestPage.

Предыдущая (разборка) пост:

Я работаю над приложением Quasar, и для удобства я хотел бы создать модифицированный метод fetch, который вводит мой ключ API, если запрошенный домен совпадает с моим внутренним доменом. Интерфейс будет примерно таким:

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

Я знаю, как дать такое определение. Мне просто нужно обновить прототип Vue согласно https://vuejs.org/v2/cookbook/adding-instance-properties.html:

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

Согласно документации Quasar, подходящее время для обновление прототипа Vue находится в загрузочном файле. Итак, я создал один:

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<Vue>, поэтому вместо этого я попробовал:

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.$fetch в компоненте:

Свойство «$ fetch» ​​не существует для типа «VueComponent».

Поскольку VueComponent extends Vue, я думаю, мне нужно обновить определение класса Vue, но я не понимаю, как это сделать. Я попытался добавить в свой загрузочный файл следующее:

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

Но это не сработало. Я не могу просто использовать declare module, потому что, опять же, я не в модуле. Как расширить тип глобально без модуля?


person stevendesu    schedule 09.10.2020    source источник
comment
Затенение вполне допустимо, но может использовать стандартный параметр или встроенное переименование. Пожалуйста, не объединяйте свои личные правила стиля с ошибками TypeScript.   -  person Aluan Haddad    schedule 09.10.2020
comment
@AluanHaddad, это честно, хотя даже работая над проблемой с Vue (vs VueConstructor), я не уверен, как обновить интерфейс Vue глобально, чтобы другие скрипты заметили новое свойство, которое я добавил   -  person stevendesu    schedule 09.10.2020
comment
Оберните последний фрагмент в declare module "vue" {}. Сделайте его модулем, добавив export {} на верхнем уровне, если вы не в модуле   -  person Aluan Haddad    schedule 09.10.2020
comment
@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 не существует?   -  person stevendesu    schedule 09.10.2020


Ответы (1)


Пример кода в моем кратком сообщении (показывающий, что я придумал после проб и ошибок) действительно работает - мне просто пришлось перезагрузить компьютер (возможно, мне просто пришлось перезапустить мою IDE, но закрытие не полностью отключало его для некоторых причина)

person stevendesu    schedule 18.10.2020