Trouble to understand types

System Information
  • Strapi Version: V5
  • Operating System: w10
  • Database: default
  • Node Version: 20.10
  • NPM Version: 10.8.3
  • Yarn Version:
- Package : 
  "dependencies": {
    "@nuxt/content": "^2.13.4",
    "@nuxtjs/strapi": "npm:@nuxtjs/strapi-edge@1.12.0-28818224.f53bdf9",
    "@nuxt/image": "^1.8.1",
    "@nuxt/scripts": "^0.9.5",
    "@pinia/nuxt": "^0.5.5",
    "axios": "^1.7.7",
    "nuxt": "^3.13.2",
    "vue": "latest",
    "vue-router": "latest"
  },
  "devDependencies": {
    "@nuxtjs/strapi": "npm:@nuxtjs/strapi-edge@1.12.0-28818224.f53bdf9",
    "autoprefixer": "^10.4.20",
    "postcss": "^8.4.47",
    "tailwindcss": "^3.4.14"
  }

nuxt.config.ts : 
export default defineNuxtConfig({
  ssr: true,
  compatibilityDate: '2024-04-03',
  devtools: { enabled: true },
  css: ['~/assets/css/main.css'],

  postcss: {
    plugins: {
      tailwindcss: {},
      autoprefixer: {},
    },
  },

  runtimeConfig: {

  },
  strapi: {
    url: process.env.STRAPI_URL || 'the localhost 1337',
    prefix: '/api',
    admin: '/admin',
    version: 'v5',
    cookie: {},
  },
  image: {
    strapi: {
      baseURL: 'the localhost 1337'
    }
  },
  alias: {
    /* permet de régler un problème entre pinia et nuxt (https://stackoverflow.com/a/74801367) */
    pinia: "/node_modules/@pinia/nuxt/node_modules/pinia/dist/pinia.mjs"
  },
  modules: ['@nuxt/scripts', '@nuxt/image', '@pinia/nuxt', '@nuxt/content', '@nuxtjs/strapi'],
})

Hello, i’m new to typescript and strapi.
I’m trying to play around strapi with nuxt but i’m failing to understand how to makes the types working.

I’m using the blog example that come with the strapi installation.
I’m copying the generated types from the backend to the frontend.
Then, for example, i’m recovering one article with findOne (nuxt/strapi edge v5).

<script setup lang="ts">
  import type {ApiArticleArticle} from "~/types/contentTypes";

  const route = useRoute()
  const strapi = useStrapi();
  const articleSlugID = route.params.slug as string;

  //  http://localhost:1337/api/articles/a-bug-is-becoming-a-meme-on-the-internet/?populate[author][populate][0]=avatar&populate=category
  const { data, pending, refresh, error } = await useAsyncData(
      'article',
      () => strapi.findOne<ApiArticleArticle>('articles', articleSlugID, {
        populate: {
          author: {
            populate: ['avatar'],
          },
          category: true,
          cover: true,
        },
        filters: {
        },
      })
  );
  const article = computed(() => data.value);
  //...

For reference, the type look like this :

export interface ApiArticleArticle extends Struct.CollectionTypeSchema {
  collectionName: 'articles';
  info: {
    description: 'Create your blog content';
    displayName: 'Article';
    pluralName: 'articles';
    singularName: 'article';
  };
  options: {
    draftAndPublish: true;
  };
  attributes: {
    author: Schema.Attribute.Relation<'manyToOne', 'api::author.author'>;
    blocks: Schema.Attribute.DynamicZone<
      ['shared.media', 'shared.quote', 'shared.rich-text', 'shared.slider']
    >;
    category: Schema.Attribute.Relation<'manyToOne', 'api::category.category'>;
    cover: Schema.Attribute.Media<'images' | 'files' | 'videos'>;
    createdAt: Schema.Attribute.DateTime;
    createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
      Schema.Attribute.Private;
    description: Schema.Attribute.Text &
      Schema.Attribute.SetMinMaxLength<{
        maxLength: 80;
      }>;
    locale: Schema.Attribute.String & Schema.Attribute.Private;
    localizations: Schema.Attribute.Relation<
      'oneToMany',
      'api::article.article'
    > &
      Schema.Attribute.Private;
    publishedAt: Schema.Attribute.DateTime;
    slug: Schema.Attribute.UID<'title'>;
    title: Schema.Attribute.String;
    updatedAt: Schema.Attribute.DateTime;
    updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
      Schema.Attribute.Private;
  };
}

But in order to retrieve the information, i have to use the code bellow :

    <!-- Vue: Property title does not exist on type Strapi5ResponseSingle<ApiArticleArticle> -->
    <h1>Title: {{ article?.title }}</h1>
    <p>Description: {{ article?.description }}</p>
    <p>Slug: {{ article?.slug }}</p>
    <p>Created At: {{ article?.createdAt }}</p>
    <p>Updated At: {{ article?.updatedAt }}</p>

    <li> Title : {{ data.data.title }} </li>
    <li> Description :  {{ data.data.description }} </li>
    <li> Slug :  {{ data.data.slug }} </li>
    <li> createdAt :  {{  data.data.createdAt }} </li>
    <li> updatedAt {{ data.data.updatedAt }} </li>
    <br/>
    <li> cover {{ data.data.cover.name }} </li>
    <li> cover {{ data.data.cover.formats.medium.url }} </li>
    <NuxtImg provider="strapi" :src="`${ data.data.cover.formats.medium.url }`" />
    <br/>
    <li> Auteur nom {{ data.data.author.name }} </li>
    <li> Auteur avatar url {{ data.data.author.avatar.formats.thumbnail.url }} </li>
    <NuxtImg provider="strapi" :src="`${ data.data.author.avatar.formats.thumbnail.url }`" />
    <br/>
    <li> {{ data.data.category.name }} </li>

Maybe i don’t understand what the essence of typing is but i don’t think my typing is working like it should. My IDE Intellij is not helping me at all and i have red everywhere.

Like :
Vue: Property title does not exist on type Strapi5ResponseSingle
Vue: Property description does not exist on type ApiArticleArticle
And so on.

Apparently, i may have to create the interfaces on my own. But with this, i’m not using the ‘contentTypes.d.ts’ anymore
Claude suggested me to try that :

// Base Media Format interface
interface MediaFormat {
  url: string;
  width: number;
  height: number;
}

// Media Formats interface
interface MediaFormats {
  thumbnail: MediaFormat;
  small: MediaFormat;
  medium: MediaFormat;
  large: MediaFormat;
}

// Media interface
interface Media {
  name: string;
  formats: MediaFormats;
  url: string;
}

// Author interface
interface Author {
  id: number;
  name: string;
  avatar: Media;
}

// Category interface
interface Category {
  id: number;
  name: string;
}

// The main Article interface that represents the data structure
export interface Article {
  id: number;
  title: string;
  description: string;
  slug: string;
  createdAt: string;
  updatedAt: string;
  publishedAt: string;
  cover: Media;
  author: Author;
  category: Category;
}

// Strapi's response wrapper type
export interface Strapi5ResponseData<T> {
  id: number;
  attributes: T;
}

export interface Strapi5ResponseMeta {
  pagination?: {
    page: number;
    pageSize: number;
    pageCount: number;
    total: number;
  };
}

export interface Strapi5ResponseSingle<T> {
  data: Strapi5ResponseData<T>;
  meta: Strapi5ResponseMeta;
}

export type ArticleResponse = Strapi5ResponseSingle<Article>;

//...
  () => strapi.findOne<ArticleResponse>('articles', articleSlugID, {
//...
  <div v-if="article">
    <h1>Title: {{ article.title }}</h1>
    <p>Description: {{ article.description }}</p>
    <p>Slug: {{ article.slug }}</p>
    <p>Created At: {{ article.createdAt }}</p>
    <p>Updated At: {{ article.updatedAt }}</p>

    <!-- Cover image -->
    <div v-if="article.cover">
      <p>Cover: {{ article.cover.name }}</p>
      <NuxtImg
          provider="strapi"
          :src="article.cover.formats.medium.url"
      />
    </div>

    <!-- Author information -->
    <div v-if="article.author">
      <p>Author: {{ article.author.name }}</p>
      <NuxtImg
          v-if="article.author.avatar"
          provider="strapi"
          :src="article.author.avatar.formats.thumbnail.url"
      />
    </div>

    <!-- Category -->
    <p v-if="article.category">
      Category: {{ article.category.name }}
    </p>
  </div>

It is better but my IDE doesn’t suggest the interfaces informations.