Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

TypeScript / Vue 3: Injecting mutating function causes TypeScript error "Object is of type 'unknown'"

Ask Question

I’m new in TypeScript and trying to use it with Vue 3 composition API and provide / inject. Let's say in parent component A I have something like this:

// Parent component A
import { provide, ref } from 'vue';
import ScoreType from "@/types/Score";
setup() {
  const score = ref<ScoreType[]>([]);
  const updateScore = (val: ScoreType) => {
    score.value.push(val);
  provide('update_score', updateScore);  

...and then want to inject updateScore function in child component B to be able to update values in parent component A (this is what docs recommend). Unfortunately, I get a TS error Object is of type 'unknown'

// Child component B
import { inject } from 'vue';
setup() {
  const updateScore = inject('update_score');
  const checkAnswer = (val: string) => {
    updateScore({ /* ScoreType object */ });  // → Object is of type 'unknown'.

What should I do to fix the TypeScript error? I couldn't find any examples about injecting update functions in TS.

Let's firstly declare a type for our updateScore() function

// @/types/score.ts
export type ScoreType = { points: number };
export type UpdateScoreFunction = (val: ScoreType) => void;

Now we need to declare an InjectionKey which will hold the type information of our provided/injected variable (function in this case). More about it in Vue docs

Let's make a separate folder to store our keys and to keep the things organized:

// @/symbols/score.ts
import { InjectionKey } from "vue";
import { UpdateScoreFunction } from "@/types/score";
export const updateScoreKey: InjectionKey<UpdateScoreFunction> = Symbol("updateScore");

In our parent component (A):

<script lang="ts">
import { defineComponent, provide, ref } from "vue";
import { ScoreType, UpdateScoreFunction } from "@/types/score";
import { updateScoreKey } from "@/symbols/score";
export default defineComponent({
  setup() {
    const score = ref<ScoreType[]>([]);
    // Actually, adding ': UpdateScoreFunction' is optional 
    const updateScore: UpdateScoreFunction = function (val: ScoreType) {
      score.value.push(val);
    // Replace the string with InjectionKey
    provide(updateScoreKey, updateScore);
    // ...
</script>

In our child component (B):

<script lang="ts">
import { defineComponent, inject } from "vue";
import { updateScoreKey } from "@/symbols/score";
export default defineComponent({
  setup() {
    // Replace the string with InjectionKey
    const updateScore = inject(updateScoreKey);
    // In case the `updateScoreKey` is not provided by the parent component..
    if (updateScore === undefined) {
      throw new Error('Failed to inject "updateScore"');
    const checkAnswer = (val: string) => {
      // ...
      // The error is gone
      updateScore({ 
        points: Math.floor(Math.random() * 100),
    // ...
</script>

Working example provided here: codesandbox.io/s/so-provide-inject

Thanks, it works. But why do we have to handle possibility of injected function being 'undefined'? I can't imagine scenario when parent (in my app) doesn't have the injected function. Is it related with composition API and composing components from "multiple pieces" maybe? – chudy91 Jun 28, 2021 at 15:54 It will be undefined if you remove provide(updateScoreKey, updateScore); from your parent component, because there will be nothing to inject in the child one. If you don't want to handle it, you can pass a second parameter to the inject() function in your child component to specify the default value: const updateScore = inject(updateScoreKey, function() { ... });. – Cheetha Jun 28, 2021 at 16:11

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.