vue icon indicating copy to clipboard operation
vue copied to clipboard

'inject' Properties are not added to the CombinedVueInstance type definition

Open StormBurpee opened this issue 5 years ago • 7 comments

Version

2.5.17

Reproduction link

https://codesandbox.io/s/rr18r3vm9p

Steps to reproduce

  1. Copy Minimal reproduction link into a local environment, and run the webpack compilation process.

OR

  1. Initialize a vue vm
let vm = new Vue({
    el: "#app",
    render: (h: any) => h(someComponent, {}),
    provide: { service: { something: "Hello, World" } }
});
  1. Try and access service in a SFC
export default Vue.extend({
    name: "someComponent",
    inject: ["service"],
    data() {
        return {
            accessService: this.service.something // Property 'service' does not exist on type CombinedVueInstance...
        }
    }
});

What is expected?

When declaring injections in a component in typescript, you should be able to access the injection with this.injection

What is actually happening?

When accessing an injection in a vue single file component, it is currently throwing an error during the webpack compilation process, stating that the injection Property 'injection' does not exist on type 'CombinedVueInstance<Vue...


Please note: that the link to minimal reproduction won't show the error logs from the webpack compiling, as it will compile successfully, but with errors. This will need to be tested in a local environment to see what is happening.

As this is in typescript, we're currently using Webpack to compile it to a single file, and then use this on our application.

The compilation will complete successfully, however will print multiple errors to the console after compiling, about not being able to access properties, etc. When running in the browser it works successfully.

We've dug around in the vue/types folder, and to the best of our knowledge think that Inject should be a part of the type DataDef or something of this sort.

Is there possibly a temporary workaround that we can use to avoid having these errors, until a fixed release is proposed?

StormBurpee avatar Oct 19 '18 02:10 StormBurpee

Yep, I come across a similar question. I have written the property "provide" in father vue-component and have used "inject" in son vue-component, but the chrome console show: [Vue warn]: Injection "color" not found. Here is my sectional code.

/********** parent / ... export default { name: "father", provide: { color: 'blue' }, components: { son }, ... / son **********/ ... export default { name: 'pagesTable', inject: ['color'], mounted(){ console.log(this.color); } } ...

And then image

XLearner avatar Oct 16 '19 08:10 XLearner

Any news on this?

Issue open >1 year. Does that mean DI is not supported with TypeScript?

klinkby avatar Dec 16 '19 20:12 klinkby

I'm working around this by modifying Vue in my component. Example:

// main.ts

import Vue from 'vue';
import App from './App.vue';

export interface Collection {
  dog: string;
  cat: number;
  cow: boolean;
}

const myCollection: Collection = {
  dog: 'dog',
  cat: 0,
  cow: false,
};

export const myServices = {
  api: 'api',
  auth: {
    do: 'something',
  },
};

new Vue({
  render: h => h(App),
  provide: {
    ...myCollection,
    ...myServices,
  },
}).$mount('#app');
// src/helpers/vue.ts

import { VueConstructor } from 'vue';

export function makeInjector<TProvider>() {
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  return function<V extends Vue, K extends keyof TProvider>(v: VueConstructor<V>, properties: K[]) {
    return v as VueConstructor<V & Pick<TProvider, K>>;
  };
}

export function makePropertySelector<TProvider>() {
  return function<K extends keyof TProvider>(properties: K[]) {
    return properties;
  };
}
// src/components/my-component.vue

import Vue from 'vue';
import { makeInjector, makePropertySelector } from '../helpers/vue';
import { Collection, myServices } from '../main';

// use a type ...
const collectionPropInjector = makeInjector<Collection>();

// ... or typeof
const serviceInjector = makeInjector<typeof myServices>();

// use propertySelector to reuse across injector and inject
const injectServices = makePropertySelector<typeof myServices>();
const services = injectServices(['auth']);

// add properties from one or many types to this Vue instance ...
export default serviceInjector(collectionPropInjector(Vue, ['dog', 'cat']), services).extend({
  // ... and inject properties as normal here
  inject: ['dog', 'cat', ...services],
  created() {
    console.log(this.dog); // 'dog'
    console.log(this.cat); // 0
    console.log(this.cow); // undefined

    console.log(this.api); // undefined
    console.log(this.auth.do); // 'something'
  },
});

Works with VSCode Intellisense as well.

wllmsash avatar Apr 13 '20 19:04 wllmsash

Been facing the same issue with my TypeScript project. I resorted to use $parent and methods in subcomponents to be accessed in descendent component. Would really appreciate if I could use DI with TypeScript.

shivam-deepsource avatar Jan 23 '21 13:01 shivam-deepsource

A temporary workaround is define it in data as optional. That worked for me.

interface IData {
  accessService: Something
  service?: Service // injected property
}

export default Vue.extend({
  name: 'someComponent',
  inject: ['Service'],
  data(): IData {
    return {
      accessService: this.service?.something
    }
  },

fgarciajulia avatar Oct 30 '21 12:10 fgarciajulia

I had to workaround this by defining fake prop for injected property. I am on vue js 2.6.13 version, I hope this gets fixed in new version.

Before

image

After workaround with fake prop

image

niraj-nagtilak1990 avatar Aug 03 '22 10:08 niraj-nagtilak1990

您好,你发送的信息我已成功接收,我会尽快回复您。Lambert Yim

XLearner avatar Aug 03 '22 10:08 XLearner

您好,你发送的信息我已成功接收,我会尽快回复您。Lambert Yim

XLearner avatar Oct 11 '22 08:10 XLearner