PaulBratslavsky / strapi-next-js-no-types

3 stars 1 forks source link

What type to use for nested components? #1

Open zynth666 opened 10 months ago

zynth666 commented 10 months ago

Hi, I need to access different components that are children of a single type called home. When I try to use the APIResponse type all the components are missing attributes, they just have an id attribute.

type HeroSection = APIResponse<'api::home.home'>['data']['attributes']['heroSection']

image

Hero should have: image

zynth666 commented 10 months ago

Our component types aren't even available in contentTypes.d.ts. yarn strapi ts:generate-types generates an extra components.d.ts file with the correct schema. Now I just need to know how to use it. :D

zynth666 commented 10 months ago

I have changed copyTypes.js to also copy components.d.ts:

// original taken from: https://strapi.io/blog/improve-your-frontend-experience-with-strapi-types-and-type-script

const fs = require("fs");
const path = require("path");

const destinationFolder = "frontendTypes"

const files = [
    {
        src: path.join(
            __dirname,
            "./types/generated/contentTypes.d.ts"
        ),
        dest: path.join(
            __dirname,
            `./${destinationFolder}/contentTypes.d.ts`
        )
    },
    {
        src: path.join(
            __dirname,
            "./types/generated/components.d.ts"
        ),
        dest: path.join(
            __dirname,
            `./${destinationFolder}/components.d.ts`
        )
    },
]

function copyFile({ src, dest }) {
    const destinationDir = path.dirname(dest);

    // Check if source file exists
    if (!fs.existsSync(src)) {
        console.error(`Source file does not exist: ${src}`);
        process.exit(1);
    }

    // Ensure destination directory exists or create it
    if (!fs.existsSync(destinationDir)) {
        fs.mkdirSync(destinationDir, { recursive: true });
    }

    // Read the source file, modify its content and write to the destination file
    const content = fs.readFileSync(src, "utf8");
    const modifiedContent = content.replace("@strapi/strapi", "@strapi/types");

    fs.writeFile(dest, modifiedContent, (err) => {
        if (err) {
            console.error(`Error writing to destination file: ${err}`);
            process.exit(1);
        } else {
            console.log(`File ${src} copied and modified successfully!`);
        }
    });
}

files.forEach(file => copyFile(file))

and now I get more type information but something is still wrong: image

hero.heading should be an array of objects (new rich-text field) image

Could this be due to the fact that this field type is relatively new?

Any help is greatly appreciated. :)

zynth666 commented 10 months ago

I have noticed another problem with multiple media entries. The data should be wrapped in an array with the data key inside the logos object like so: image

However, the typings for this field are like this: image

As if I had only one image as opposed to many...

Again, I don't know if I am doing anything wrong here, or if it's an issue with types.ts.

PaulBratslavsky commented 10 months ago

@zynth666 thanks for the help. And yes, you do need to copy the components.d.ts file so thank you for updating the copyTypes script, I will update it in the repo.

As for the second part of your question I will look into it and see if its a bug or not.

zynth666 commented 10 months ago

@PaulBratslavsky thanks for taking a look. And you're welcome. 👍

guybinya commented 7 months ago

@PaulBratslavsky Is there a nice way to use only the media type for nested components? for example:

import React from 'react';
import Image from 'next/image';
import type { ImageProps } from 'next/dist/shared/lib/get-img-props';

interface ICustomImage extends Partial<ImageProps> {
    imageData: [InsertStrapiImageType];
}

const CustomImage: React.FC<ICustomImage> = ({ imageData, ...props }) => {
    const { url, alternativeText, width, height } = imageData.data.attributes
    return (
        <Image {...props} src={(props.src || `${url}`) as any} alt={props.alt || alternativeText || ''}
               width={props.width || width} height={props.height || height}/>
    )
}

export default CustomImage;

I'm using it like this: imageData.data.attributes

freddieerg commented 5 months ago

I have noticed another problem with multiple media entries. The data should be wrapped in an array with the data key inside the logos object like so: image

However, the typings for this field are like this: image

As if I had only one image as opposed to many...

Again, I don't know if I am doing anything wrong here, or if it's an issue with types.ts.

Hey guys, I believe this is still an issue, any help would be appreciated :)

EDIT

Looks like this is actually an issue with the types being generated by strapi, there is a PR that would fix this issue: https://github.com/strapi/strapi/pull/19329

Any bumping on it would be extremely appreciated.