1

I'm trying to use a child component to separate the display of some stuff (the async result of a db query). I tried provide/inject system from Vue to pass variables between the components. It works but still the child component seems to complain.
This is a subset of the code to give an idea.

In my parent component:

<template>
  <InteractionResults /> <!-- the child -->
</template>  

<script setup lang="ts">
import { ref, provide } from 'vue';

const loading = ref<boolean>(false);
const error = ref<boolean>(false);
    
let interactions = ref<Interaction[]>([]);
    
provide('search', { error, loading, interactions })
</script>

In my child component (InteractionResults):

<template>
  <h6>interactionResults</h6>
  {{loading}} 
<template> 

<script setup lang="ts">
import { inject } from 'vue';
import type { Interaction } from '@/models/Interaction'; 

const { error, loading, interactions } = inject('search');
// It complains and the 3 variables are highlighted in red.
</script>

The code is working but VS Code complains as follows (interactions for example, but the two other variables give the same error with their respective names):

Property 'interactions' does not exist on type '{ error: any; loading: any; interactions: any; } | undefined'.ts(2339)

7
  • inject cannot guarantee that that the value for a key was ever provide-ed, so the return type includes a union with undefined. undefined obviously has no properties, resulting in the error given by TypeScript. Commented Jan 4, 2023 at 15:51
  • See the types and explanation in the docs for inject(). Commented Jan 4, 2023 at 15:53
  • Thanks for your reply. I don't understand very well the doc from the link you provided.It would be nice if you could provide an example what the code should be for "loading" for example and also in the case or a ref(). I tried to add a default value for "loading" in the inject part without success. Commented Jan 4, 2023 at 16:57
  • While I do recommend learning how to use provide/inject, is this the best method for this case? Based on the code you've given, I would say that a prop (or props) on the child component would be better. Commented Jan 4, 2023 at 18:05
  • 1
    You are using an object, so you would need a default for the entire object. Something like { error: undefined, loading: false, interactions: [] }. See also the docs on typing provide/inject for how to use them properly and safely with TypeScript. Commented Jan 4, 2023 at 18:08

1 Answer 1

3

As per documentation:

When using string injection keys, the type of the injected value will be unknown, and needs to be explicitly declared via a generic type argument:

const foo = inject<string>('foo') // type: string | undefined

Notice the injected value can still be undefined, because there is no guarantee that a provider will provide this value at runtime.


In your specific case, it means you have to specify the type explicitly as a type argument for inject and also provide a default value, which would be used in the case in which the provider does not provide a value at runtime:

import { inject } from "vue"
import type { Interaction } from "@/models/Interaction"

interface SearchInterface {
  error: unknown
  loading: boolean
  interactions: Interaction[]
}
const defaultSearch: SearchInterface = {
  error: null,
  loading: false,
  interactions: []
}
const { error, loading, interactions } =
  inject<SearchInterface>("search") || defaultSearch

Without the default value, TS will object, since undefined cannot be destructured.


If you need to do the above in multiple places, it might make sense to place the interface declaration and default value into a separate file and import them from there, to keep your code DRY.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.