What could be triggering the "slice is not defined" error in this TypeScript and Vue 3 application?

I have been developing a Single Page Application using Vue 3, TypeScript, and the The Movie Database (TMDB) API.

In my src\components\MovieDetails.vue file, I have implemented the following:

<template>
  <div class="row">
    <div class="col-sm-4 col-md-3">
      <div class="poster-container text-center text-sm-start my-3">
        <img v-if="movie"
          :src="genericPoster"
          :alt="movie?.title"
          class="img-fluid shadow-sm"
        />
      </div>
    </div>

    <div class="col-sm-8 col-md-9">
      <h1 class="movie-title mt-4">{{ movie?.original_title }}</h1>

      <p v-if="movie?.genres.length">
        <strong class="pe-1">Genres:</strong>
        <span
          class="badge bg-secondary"
          v-for="genre in movie?.genres"
          :key="genre.id"
          >{{ genre.name }}</span
        >
      </p>

      <p v-if="movie?.vote_average" class="user-score">
        <strong>User Score:</strong>
        <span class="score" :class="movieQuality">{{
          Number(movie?.vote_average).toFixed(2)
        }}</span>
      </p>

      <div v-if="movie?.overview">
        <h2 class="section-title">Overview</h2>
        <p>{{ movie.overview }}</p>
      </div>

      <div v-if="movieTrailers.length" class="mb-3">
        <h2 class="section-title">Trailers</h2>
        <TrailerCarousel :movieTrailers="movieTrailers" />
      </div>

      <div v-if="movieCast.length" class="cast-container">
        <h2 class="section-title">Cast</h2>
        <div class="row">
          <div
            v-for="actor in movieCast.slice(0, 12)"
            :key="actor['id']"
            class="col-sm-3"
          >
            <ActorCard :actor="actor" />
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent } from "vue";
import { useRoute } from "vue-router";
import env from "../env";
import { Movie } from "@/models/Movie";
import { Trailer } from "@/models/Trailer";
import { MovieCast } from "@/models/MovieCast";
import TrailerCarousel from "./TrailerCarousel.vue";
import ActorCard from "./ActorCard.vue";

export default defineComponent({
  name: "MovieDetails",

  components: {
    TrailerCarousel,
    ActorCard,
  },

  data: () => ({
    route: useRoute(),
    genericPosterBig: require('../assets/generic-poster.png'),
    movie: null as Movie | null,
    movieQuality: String as unknown | 'bad',
    movieCast: Array as unknown | MovieCast[],
    movieTrailers: Array as unknown | Trailer[]
  }),

  mounted() {
    this.getMovieDetails();
    this.getMovieTrailers();
    this.getMovieCast();
  },

  methods: {
    getMovieDetails() {
      this.$axios
        .get(
          `${env.api_url}/movie/${this.route.params.id}?api_key=${env.api_key}`
        )
        .then((response) => {
          this.movie = response.data;
          // Set the movie quality once it's retrieved
          this.setMovieQuality();
        })
        .catch((err) => console.log(err));
    },

    setMovieQuality() {
      if (Number(this.movie?.vote_average) >= 7) {
         this.movieQuality = 'good';
      } else if(Number(this.movie?.vote_average) < 7 && Number(this.movie?.vote_average) > 5.5) {
         this.movieQuality =  'average';
      } else {
         this.movieQuality =  'bad';
      }
    },

    getMovieTrailers() {
      this.$axios
        .get(
          `${env.api_url}/movie/${this.route.params.id}/videos?api_key=${env.api_key}`
        )
        .then((response) => {
          this.movieTrailers = response.data.results;
        })
        .catch((err) => console.log(err));
    },

    getMovieCast() {
      this.$axios
        .get(
          `${env.api_url}/movie/${this.route.params.id}/credits?api_key=${env.api_key}`
        )
        .then((response) => {
          this.movieCast = response.data.cast;
        })
        .catch((err) => console.log(err));
    },
  },

  computed: {
    genericPoster() {
      return !this.movie?.poster_path
        ? this.genericPosterBig
        : `https://image.tmdb.org/t/p/w500/${this.movie?.poster_path}`;
    },
  },

  watch: {
    "$route.params.id"() {
      this.getMovieDetails();
      this.getMovieTrailers();
      this.getMovieCast();
    },
  },
});
</script>

In the src\models\MovieCast.ts file:

export interface MovieCast {
    adult?: boolean;
    character?: string;
    name?: string;
    profile_path?: string;
}

Instead of the previous lines in the components:

movieCast: Array as unknown | MovieCast[]
movieTrailers: Array as unknown | Trailer[]

I initially had:

movieTrailers: [],
movieCast: [],

I decided to make this change to ensure a more strictly typed application.

The Issue

However, after making this update, the console error displayed is:

TypeError: _ctx.movieCast.slice is not a function

<div
    v-for="actor in movieCast.slice(0, 12)"
    :key="actor['id']"
    class="col-sm-3"
  >
    <ActorCard :actor="actor" />
</div>

A working demonstration of the app can also be found on Stackblitz.

Queries

  1. What could be the mistake I am making?
  2. What would be the most effective way to resolve this issue?

Answer №1

If you encounter an error when assigning a non-array, try logging the type to see what is being returned.

console.log('movieCast', response.data.cast)
this.movieCast = response.data.cast;

To avoid errors while your async value is undefined and calculating, use a conditional operator. You can also wrap the v-for in a v-if statement to check for undefined.

v-for="actor in movieCast?.slice(0, 12)"

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Should ts-node be avoided in a production environment due to potential risks?

My current setup involves using ts-node with express in production and so far, it's been functioning smoothly. Am I missing out on any benefits by not compiling and running .js files instead? ...

What is the proper way to incorporate types in a universal function?

Encountering an issue with TypeScript while using a universal function export const createNewArray = <T>( arr: T[], keyId: keyof T, keyTitle: keyof T, ) : [] | TValue[] => { const arrayAfterMap = arr.map((item) => ({name: item[ ...

Display the React component following a redirect in a Next.js application that utilizes server-side rendering

Just starting out with next.js and encountering a problem that I can't seem to solve. I have some static links that are redirecting to search.tsx under the pages folder. Current behavior: When clicking on any of the links, it waits for the API respo ...

Guide to utilizing the sendEmailVerification() functionality in Angular

I'm currently working on setting up an email verification system using Angular and the Google Firebase API. I came across the sendEmailVerification() function through this reference, but I'm a bit unsure about how to correctly implement it. To ad ...

Transmitting data from Angular to .NET Core for seamless integration

I have been attempting to send an xls or any other file from my angular application to a .NET core controller, but none of my methods seem to work... Below is my component where I call my service upon button click: handleFileInput(file: FileList) { this. ...

Created computed getter and setter for Vue models (also known as "props") using the syntax of Vue Class Component

After exploring the limitations of v-model in Vue 2.x in this Stack Overflow thread, I discovered a way to connect parent and child components using v-model. The solution proposed is as follows: --- ParentTemplate: <Child v-model="formData"> ...

Typescript: Extracting data from enum items using types

I am facing a challenge with an enum type called Currency. I am unable to modify it because it is automatically generated in a graphql schema. However, I need to utilize it for my data but I'm unsure of how to go about doing so. enum Currency { rub ...

Unexpected outcome when returning a map

Encountered a puzzling issue that requires immediate clarification. When I input the following code into my project: this.metadata = json.metadata.map((x) => {return new Metadatum(x);}); console.log(this.metadata[0].value); The output consistently sho ...

Choose datetime datepicker formatting in ng-pick

Currently, I am utilizing Angular and have incorporated the ng-pick-datetime npm. However, when attempting to adjust the format after selecting a date (dd/MM/yyyy), it consistently displays as (MM/dd/yyyy) instead. I am uncertain about how to rectify this ...

The @input field is failing to show the value entered by the user

I'm having trouble with my dynamic reactive form, as the value is not showing up <div *ngFor="let deliveryAcross of (deliveriesAcross | async)!; let i = index;"> <app-delivery-across [index]="i" [deliveryAcross]= ...

Tips for resolving the CROSS Origin problem within ionic-vue

Recently, I started exploring the world of Ionic framework with Vuejs and decided to create a basic Crud app. Unfortunately, I'm facing some CORS issues that are preventing me from being able to login. My browser console is displaying an error messag ...

Utilizing generic type and union types effectively in TypeScript

When initializing my class, I often pass in either a value or an object containing information about the value. For instance: new Field<string>('test') new Field<string>({value: 'test', inactive: 'preview'}) Howev ...

When bootstrap buttons are displayed inside a Vue component, there should be no spacing between them

Is this issue specific to the vue-loader or is it more related to webpack builds in general? Consider a basic HTML page with Bootstrap 4 loaded and two buttons added: <button type="button" class="btn btn-primary">Primary</button> <button t ...

Whenever I attempt to execute yarn build within next.js, an error always seems to occur

When attempting to compile my next.js project using the yarn build command, an error consistently occurs: Error: Export encountered errors on following paths: /settings at D:\web3\futnft\frontend\node_modules\next\ ...

How do I inform Jest that spaces should be recognized as spaces?

Here is some code snippet for you to ponder: import { getLocale } from './locale'; export const euro = (priceData: number): string => { const priceFormatter = new Intl.NumberFormat(getLocale(), { style: 'currency', currenc ...

Obtaining an identification number upon clicking within a Vue table and storing it in a Laravel controller

One of the challenges I'm facing is related to an action button that triggers a modal to open. Within this modal, there's a component where users can upload an image. However, I'm currently struggling with retrieving the ID of the item that ...

Removing the AM and PM from OwlDateTime in Angular is simple since the time format is already in 24-hour time

Using OwlDateTime in a 24-hour format: <div *ngIf="isSchedule" class="form-inline"> <label style='margin-right:5px ;margin-left:210px'> Date Time: <input [owlDateTimeTrigger]="dt" [owlDateTime]="dt" class="form-control" placeh ...

Tips for enabling custom object properties in Chrome DevTools

In my typescript class, I am utilizing a Proxy to intercept and dispatch on get and set operations. The functionality is working smoothly and I have successfully enabled auto-completion in vscode for these properties. However, when I switch to the chrome d ...

The MongoDB connection in NextJS 14 is causing a delay in loading the page

Occasionally, when trying to open a page through the dashboard menu, nothing happens on the frontend. There's no loading screen or any indication that the page is being loaded. How can this problem be prevented so that the page loads as intended? This ...

What is the reason behind not being able to pass an instance of B to an argument a of type T in Typescript generics when T extends B?

There is a problem with my code: class X<T extends B> [...] // this.p.a :: B | null methodA(a: T):void {[...]} methodB(): void { if(this.p.a){ // :: B this.methodA(this.p.a) // Error My intention was for T to be any type that exten ...