Home > other >  Inject / Provide with typescript in vue3 : Property '?' does not exist on type '{ err
Inject / Provide with typescript in vue3 : Property '?' does not exist on type '{ err

Time:01-06

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)

CodePudding user response:

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.

  • Related