Type reference provision/injection functionality in VueJS
P粉441076405
2023-09-04 16:34:30
<p>I'm trying to provide a typed ref from a parent component and inject it into the child component. </p>
<p>I'm not sure if I understand the VueJS documentation, but this is what I came up with. </p>
<pre class="brush:php;toolbar:false;">import type { Ref } from 'vue'
import type { InjectionKey } from 'vue'
import type DocumentSet from '@/types/DocumentSet'
const documentSet = Symbol() as InjectionKey<{
documentSet: Ref<DocumentSet>,
update: () => void
}>
export default documentSet</pre>
<p>So, the task is to provide a typed object (in my case a documentSet), and a function that updates it. </p>
<p>Now, in the parent component I have this code: </p>
<pre class="brush:php;toolbar:false;">import dsKey from '@/injectionKeys/documentSet'
import type DocumentSet from '@/types/DocumentSet'
...
const documentSet = ref<DocumentSet | null>(null)
provide(dsKey, {
documentSet,
update: () => console.log('update')
})</pre>
<p>And in the child component I have this code: </p>
<pre class="brush:php;toolbar:false;">import dsKey from '@/injectionKeys/documentSet'
const ds = inject(dsKey)
const documentSet = ds?.documentSet</pre>
<p>The problem is, since there is a lot of boilerplate code, I feel like I'm doing something wrong. For example, I can't understand why the ds object should be refactored like this: </p>
<pre class="brush:php;toolbar:false;">const { documentSet } = ds</pre>
<p>Is it possible to shorten the code instead of writing <code>ds?.documentSet</code>, especially if I'm sure that ds should exist (without it I won't render the child component)</p>
<p>If I write <code>const { documentSet } = inject(dsKey)</code>, the following error will appear: </p>
<p><code>TS2339: Property 'documentSet' does not exist on type '{ documentSet: Ref ;' Update: () => Invalid; } | Undefined '.</code></p>
<p>The idea is because I want to eliminate duplication in child components: </p>
<pre class="brush:php;toolbar:false;"><DocumentSetInfo
:documentSet="documentSet"
/>
<DocumentSetMemos
:documentSet="documentSet"
/>
<DocumentSetPrograms
:documentSet="documentSet"
/>
<DocumentSetPetition
:documentSet="documentSet"
/>
<DocumentSetPassRequests
:documentSet="documentSet"
/>
<DocumentSetReport
:documentSet="documentSet"
/>
<DocumentSetReceptionNotices
:documentSet="documentSet"
/></pre></p>
You can put this into a composable that provides a function provde that handles provision and a function use* that handles injection:
Now you only need to call
provideCurrentDocumentSet()
in the parent component, and all child components only need to perform the following operations:You don't even need to export the InjectionKey, and the component doesn't need to know about it. (For example, Vuetify also does this, for example here)