Type-safe context injections in Vue.js (a-la React)

Ismayil Khayredinov
1 min readJul 5, 2024

--

I find provide and inject in Vue.js to be quite limiting, so I wrote some syntactic sugar to get the most out of them. I do prefer context providers in React, so you will notice some similarities.

Thanks to this method, I do not need to pollute my global scope and can contextualize my state as needed. This inversion of control makes testing much simpler, and allows me to reuse components across the app without worrying much about leaking state.

Provider Factory

import { inject, provide } from 'vue';

export const defineProvider = <T, A extends unknown[]>(name: string, fn: (...args: A) => T) => {
const injectionKey = Symbol(name);

return {
provide: (...args: Parameters<typeof fn>) => {
const ctx = fn(...args);
provide<T>(injectionKey, ctx);
return ctx;
},
inject: () => {
const ctx = inject(injectionKey);
if (!ctx) {
throw new Error('You must create a context before using it');
}
return ctx as T;
},
};
};

Context Factory

const createMyContext = (b: string) => {
return {
a: 1,
b
}
}

const { provide, inject } = defineProvider('MyContext', createMyContext);

export { provide as provisionMyContext, inject as useMyContext };

Provider Component

<script setup>
import { provisionMyContext } from './context'

const ctx= provisionMyContext(b)
</script>

<template>
b is {{ ctx.b }}
</template>

Child Component

<script setup>
import { useMyContext } from './context'

const ctx= useMyContext()
</script>

<template>
b is {{ ctx.b }}
</template>

Bisous.

--

--

Ismayil Khayredinov
Ismayil Khayredinov

Written by Ismayil Khayredinov

Software engineer who combines optimism with pessimism to build robust and idiot-proof solutions

No responses yet