Error when using composable and reactive in Ionic Vue

I’m trying to use the Composition API with Ionic Vue but it’s throwing an error when trying to compile. The error is coming from the use-song-list.ts and the errors I’m getting are

Type 'Ref<never[]>' is missing the following properties from type 'never[]': length, pop, push, concat, and 28 more.

Type 'Ref<null>' is not assignable to type 'null'.

Type 'Ref<boolean>' is not assignable to type 'boolean'.

What am I doing wrong? Why can’t I assign the response, error and fetching constants to the songs object properties?

Below is my code.

Tab1.vue

<script lang="ts">
import {
  IonPage,
  IonHeader,
  IonToolbar,
  IonTitle,
  IonContent,
  IonList,
  IonItem,
} from "@ionic/vue";
import { reactive } from "vue";
import useSongList from "./../composables/use-song-list";

export default {
  name: "Tab1",
  components: {
    IonHeader,
    IonToolbar,
    IonTitle,
    IonContent,
    IonPage,
    IonList,
    IonItem,
  },
  setup() {
    const { list, error, fetching } = useSongList();

    return {
      list,
      error,
      fetching,
    };
  },
};
</script>

useSongList.ts

import { reactive, Ref, toRefs } from 'vue';
import useFetch from './use-fetch';

export default function () {
    let songs = reactive({ list: [], error: null, fetching: false });

    const { response, error, fetchData, fetching } = useFetch("ENDPOINT_CHANGED", {});

    fetchData();

    // This is where the errors are happening.
    songs.list = response;
    songs.error = error;
    songs.fetching = fetching;

    return { ...toRefs(songs) };
}

fetchData.ts

import { reactive, Ref, toRefs } from 'vue';

export default function (endpoint: RequestInfo, options: Object) {
    const state = reactive({
        response: [],
        error: null,
        fetching: false
    });

    const fetchData = async () => {
        state.fetching = true;

        try {
            const res = await fetch(endpoint, options);
            const json = await res.json();
            state.response = json;
        } catch (errors) {
            state.error = errors;
        } finally {
            state.fetching = false;
        }
    };

    return { ...toRefs(state), fetchData };
}

that is the magic of typescript, change your code to this…

    const state = reactive({
      response: [] as Array<any>,
      error: null,
      fetching: false,
    });

Thank you for your help @aaronksaunders. It was one of your videos I was watching that got me started on this, so thank you I think. :slight_smile:

I had made some updates to my code which involved using interfaces and this resolved the original issue but I’m not sure if these interfaces are correct.

I now get the response from the API call but I’m unable to use the list object in the Tab1.vue component. When I log list in Tab1.vue I get ObjectRefImpl {_object: Proxy, _key: "list", __v_isRef: true}.

Or when I log list.value I get Proxy {}. I might open a different question for this.

My use-fetch.ts I updated to the below.

import { reactive, toRefs } from 'vue';

interface FetchState {
    response: any;
    error: string | null;
    fetching: boolean;
}

export default function (endpoint: RequestInfo, options: Record<string, any>) {
    const state: FetchState = reactive({
        response: [],
        error: null,
        fetching: false
    });

    const fetchData = async () => {
        state.fetching = true;

        try {
            const res = await fetch(endpoint, options);
            const json = await res.json();
            state.response = json;
        } catch (errors) {
            state.error = errors;
        } finally {
            state.fetching = false;
        }
    };

    return { ...toRefs(state), fetchData };
}

and my use-song-list.ts

import { reactive, toRefs } from 'vue';
import useFetch from './use-fetch';

interface SongsData {
    list: any;
    error: any;
    fetching: any;
}

export default function () {
    const songs: SongsData = reactive({ list: [], error: null, fetching: false });

    const { response, error, fetchData, fetching } = useFetch("ENDPOINT_CHANGED", {});

    fetchData();

    songs.list = response;
    songs.error = error;
    songs.fetching = fetching;

    return { ...toRefs(songs) };
}