类型错误:' post'指一个值,但在这里被用作类型。您的意思是' typeof post&#x27 ;?
我制作了一个具有NextJS + Sanity的博客应用程序,但我的[Slug] .TSX上有一个错误,
我会遇到错误:
类型错误:'post'是指一个值,但被用作类型 这里。您是说“ type of post”?
该文件具有.tsx扩展名,并且帖子接口在Typings.d.ts文件上声明。我在其他解决方案上阅读了我应该确保.tsx是扩展名而不是.ts,但这也指打字文件吗?因为我试图将.TS文件更改为.tsx,但它无法解决。
如果我将帖子更改为 typeof post 错误会消失,但是当调用邮政属性时会出现很多警告。
[slug] .tsx文件
import { GetStaticProps } from 'next'
import React, { useState } from 'react'
import Header from '../../components/Header'
import { sanityClient, urlFor } from '../../sanity'
import PortableText from 'react-portable-text'
import { useForm, SubmitHandler } from 'react-hook-form'
interface IFormInput {
_id: string;
name: string;
email: string;
comment: string;
}
interface Props {
post: Post;
}
export default function Post({ post }: Props) {
const [submitted, setSubmitted] = useState(false);
console.log(post);
const {
register,
handleSubmit,
formState: { errors }
} = useForm<IFormInput>()
const onSubmit: SubmitHandler<IFormInput> = (data) => {
fetch('/api/createComment', {
method: 'POST',
body: JSON.stringify(data),
}).then(() => {
console.log(data);
setSubmitted(true);
}).catch((err) => {
console.log(err);
setSubmitted(false);
})
};
return (
<main>
<Header />
<img
className='w-full h-40 object-cover'
src={urlFor(post.mainImage).url()!}
alt="" />
<article className='max-w-3xl mx-auto p-5'>
<h1 className='text-3xl mt-10 mb-3 font-extrabold text-[#292929] '>{post.title}</h1>
<h2 className='text-xl font-light text-gray-500 mb-2'>{post.description}</h2>
<div className='flex items-center space-x-2'>
<img className='h-10 w-10 rounded-full' src={urlFor(post.author.image).url()!} alt="" />
<p className='font-extralight text-sm'>
Blog post by <span className='text-green-600'>{post.author.name}</span> - Published at {new Date(post._createdAt).toLocaleString()}
</p>
</div>
<div className='mt-10'>
<PortableText
className=''
dataset={process.env.NEXT_PUBLIC_SANITY_DATASET!}
projectId={process.env.NEXT_PUBLIC_SANITY_PROJECT_ID!}
content={post.body}
serializers={{
h1: (props: any) => (
<h1 className='text-2xl font-bold my-5' {...props} />
),
h2: (props: any) => (
<h2 className='text-xl font-bold my-5' {...props} />
),
li: ({ children }: any) => (
<li className='ml-4 list-disc'>{children}</li>
),
link: ({ href, children }: any) => (
<a href={href} className='text-blue-500 hover:underline'>
{children}
</a>
),
}}
/>
</div>
</article>
<hr className='max-w-lg my-5 mx-auto border border-yellow-500' />
{submitted ? (
<div className='flex flex-col p-10 my-10 bg-yellow-500 text-white max-w-2xl mx-auto'>
<h3 className='text-3xl font-bold'>
Thank you for submitting your comment!
</h3>
<p>Once it has been approved, it will appear below!</p>
</div>
): (
<form onSubmit={handleSubmit(onSubmit)} className='flex flex-col p-5 max-w-2xl mx-auto mb-10' action="">
<h3 className='text-sm text-yellow-500'>Enjoyed this article?</h3>
<h4 className='text-3xl font-extrabold text-[#292929]'>Leave a comment below!</h4>
<hr className='py-3 mt-2' />
<input
{...register("_id")}
type="hidden"
name="_id"
value={post._id}
/>
<label className='block mb-5'>
<span className='text-gray-700'>Name</span>
<input {...register("name", {required: true})}
className='shadow border rounded py-2 px-3 form-input mt-1 block w-full ring-yellow-500 focus:ring-1 focus:outline-none' type="text" name="name" placeholder='John Appleseed' />
</label>
<label className='block mb-5'>
<span className='text-gray-700'>Email</span>
<input {...register("email", {required: true})}
className='shadow border rounded py-2 px-3 form-input mt-1 block w-full ring-yellow-500 focus:ring-1 focus:outline-none' placeholder='John Appleseed' type="text" />
</label>
<label className='block mb-5'>
<span className='text-gray-700'>Comment</span>
<textarea {...register("comment", {required: true})}
className='shadow border rounded py-2 px-3 mt-1 block w-full ring-yellow-500 focus:ring-1 focus:outline-none' placeholder='John Appleseed' rows={8} />
</label>
{/* errors will return when field validation fails */}
<div className='flex flex-col p-5'>
{errors.name && (<span className='text-red-500'>- The Name field is required</span>)}
{errors.comment && (<span className='text-red-500'>- The Comment field is required</span>)}
{errors.email && (<span className='text-red-500'>- The Email field is required</span>)}
</div>
<input className='shadow bg-yellow-500 hover:bg-yellow-400 transition-colors focus:shadow-outline focus:outline-none text-white font-bold py-2 px-4 rounded cursor-pointer' type="submit" />
</form>
)}
{/* Comments */}
<div className='flex flex-col p-10 my-10 max-w-2xl mx-auto shadow-yellow-500 shadow space-y-2'>
<h3 className='text-4xl font-extrabold text-[#292929]'>Comments</h3>
<hr className='pb-2' />
{post.comments.map((comment) => (
<div key={comment._id}>
<p><span className='text-yellow-500'>{comment.name}: </span>{comment.comment}</p>
</div>
))}
</div>
</main>
);
}
export const getStaticPaths = async () => {
const query = `*[_type == "post"]{
_id,
slug {
current
}
}`;
const posts = await sanityClient.fetch(query);
const paths = posts.map((post: Post) => ({
params: {
slug: post.slug.current,
},
}));
return {
paths,
fallback: 'blocking',
};
};
export const getStaticProps: GetStaticProps = async ({params}) => {
const query = `*[_type == "post" && slug.current == $slug][0]{
_id,
_createdAt,
title,
author-> {
name,
image
},
'comments': *[
_type == "comment" &&
post._ref == ^._id &&
approved == true],
description,
mainImage,
slug,
body
}`
const post = await sanityClient.fetch(query, {
slug: params?.slug,
});
if (!post) {
return {
notFound: true
}
}
return {
props: {
post,
},
revalidate: 60, // after 60s it will update the old cached version
}
}
typings.d.ts file
export interface Post {
_id: string;
_createdAt: string;
title: string;
author: {
name: string;
image: string;
};
comments: Comment[];
description: string;
mainImage: {
asset: {
url: string;
};
};
slug: {
current: string;
};
body: [object];
}
export interface Comment {
approved: boolean;
comment: string;
email: string;
name: string;
post: {
_ref: string;
_type: string;
};
_createdAt: string;
_id: string;
_rev: string;
_type: string;
_updatedAt: string;
}
I made a blog app with Nextjs + Sanity but I'm having an error on my [slug].tsx
I'm getting the error:
Type error: 'Post' refers to a value, but is being used as a type
here. Did you mean 'typeof Post'?
The file has the .tsx extension and Post interface is declared on a typings.d.ts file. I read on other solutions that I should make sure that .tsx is the extension instead of .ts but does that refer also to the typings file? Because I tried to change the .ts file into .tsx but it doesn't get solved.
If I change the Post to typeof Post error disappears but then a lot of warning appears when calling properties of Post.
[slug].tsx file
import { GetStaticProps } from 'next'
import React, { useState } from 'react'
import Header from '../../components/Header'
import { sanityClient, urlFor } from '../../sanity'
import PortableText from 'react-portable-text'
import { useForm, SubmitHandler } from 'react-hook-form'
interface IFormInput {
_id: string;
name: string;
email: string;
comment: string;
}
interface Props {
post: Post;
}
export default function Post({ post }: Props) {
const [submitted, setSubmitted] = useState(false);
console.log(post);
const {
register,
handleSubmit,
formState: { errors }
} = useForm<IFormInput>()
const onSubmit: SubmitHandler<IFormInput> = (data) => {
fetch('/api/createComment', {
method: 'POST',
body: JSON.stringify(data),
}).then(() => {
console.log(data);
setSubmitted(true);
}).catch((err) => {
console.log(err);
setSubmitted(false);
})
};
return (
<main>
<Header />
<img
className='w-full h-40 object-cover'
src={urlFor(post.mainImage).url()!}
alt="" />
<article className='max-w-3xl mx-auto p-5'>
<h1 className='text-3xl mt-10 mb-3 font-extrabold text-[#292929] '>{post.title}</h1>
<h2 className='text-xl font-light text-gray-500 mb-2'>{post.description}</h2>
<div className='flex items-center space-x-2'>
<img className='h-10 w-10 rounded-full' src={urlFor(post.author.image).url()!} alt="" />
<p className='font-extralight text-sm'>
Blog post by <span className='text-green-600'>{post.author.name}</span> - Published at {new Date(post._createdAt).toLocaleString()}
</p>
</div>
<div className='mt-10'>
<PortableText
className=''
dataset={process.env.NEXT_PUBLIC_SANITY_DATASET!}
projectId={process.env.NEXT_PUBLIC_SANITY_PROJECT_ID!}
content={post.body}
serializers={{
h1: (props: any) => (
<h1 className='text-2xl font-bold my-5' {...props} />
),
h2: (props: any) => (
<h2 className='text-xl font-bold my-5' {...props} />
),
li: ({ children }: any) => (
<li className='ml-4 list-disc'>{children}</li>
),
link: ({ href, children }: any) => (
<a href={href} className='text-blue-500 hover:underline'>
{children}
</a>
),
}}
/>
</div>
</article>
<hr className='max-w-lg my-5 mx-auto border border-yellow-500' />
{submitted ? (
<div className='flex flex-col p-10 my-10 bg-yellow-500 text-white max-w-2xl mx-auto'>
<h3 className='text-3xl font-bold'>
Thank you for submitting your comment!
</h3>
<p>Once it has been approved, it will appear below!</p>
</div>
): (
<form onSubmit={handleSubmit(onSubmit)} className='flex flex-col p-5 max-w-2xl mx-auto mb-10' action="">
<h3 className='text-sm text-yellow-500'>Enjoyed this article?</h3>
<h4 className='text-3xl font-extrabold text-[#292929]'>Leave a comment below!</h4>
<hr className='py-3 mt-2' />
<input
{...register("_id")}
type="hidden"
name="_id"
value={post._id}
/>
<label className='block mb-5'>
<span className='text-gray-700'>Name</span>
<input {...register("name", {required: true})}
className='shadow border rounded py-2 px-3 form-input mt-1 block w-full ring-yellow-500 focus:ring-1 focus:outline-none' type="text" name="name" placeholder='John Appleseed' />
</label>
<label className='block mb-5'>
<span className='text-gray-700'>Email</span>
<input {...register("email", {required: true})}
className='shadow border rounded py-2 px-3 form-input mt-1 block w-full ring-yellow-500 focus:ring-1 focus:outline-none' placeholder='John Appleseed' type="text" />
</label>
<label className='block mb-5'>
<span className='text-gray-700'>Comment</span>
<textarea {...register("comment", {required: true})}
className='shadow border rounded py-2 px-3 mt-1 block w-full ring-yellow-500 focus:ring-1 focus:outline-none' placeholder='John Appleseed' rows={8} />
</label>
{/* errors will return when field validation fails */}
<div className='flex flex-col p-5'>
{errors.name && (<span className='text-red-500'>- The Name field is required</span>)}
{errors.comment && (<span className='text-red-500'>- The Comment field is required</span>)}
{errors.email && (<span className='text-red-500'>- The Email field is required</span>)}
</div>
<input className='shadow bg-yellow-500 hover:bg-yellow-400 transition-colors focus:shadow-outline focus:outline-none text-white font-bold py-2 px-4 rounded cursor-pointer' type="submit" />
</form>
)}
{/* Comments */}
<div className='flex flex-col p-10 my-10 max-w-2xl mx-auto shadow-yellow-500 shadow space-y-2'>
<h3 className='text-4xl font-extrabold text-[#292929]'>Comments</h3>
<hr className='pb-2' />
{post.comments.map((comment) => (
<div key={comment._id}>
<p><span className='text-yellow-500'>{comment.name}: </span>{comment.comment}</p>
</div>
))}
</div>
</main>
);
}
export const getStaticPaths = async () => {
const query = `*[_type == "post"]{
_id,
slug {
current
}
}`;
const posts = await sanityClient.fetch(query);
const paths = posts.map((post: Post) => ({
params: {
slug: post.slug.current,
},
}));
return {
paths,
fallback: 'blocking',
};
};
export const getStaticProps: GetStaticProps = async ({params}) => {
const query = `*[_type == "post" && slug.current == $slug][0]{
_id,
_createdAt,
title,
author-> {
name,
image
},
'comments': *[
_type == "comment" &&
post._ref == ^._id &&
approved == true],
description,
mainImage,
slug,
body
}`
const post = await sanityClient.fetch(query, {
slug: params?.slug,
});
if (!post) {
return {
notFound: true
}
}
return {
props: {
post,
},
revalidate: 60, // after 60s it will update the old cached version
}
}
typings.d.ts file
export interface Post {
_id: string;
_createdAt: string;
title: string;
author: {
name: string;
image: string;
};
comments: Comment[];
description: string;
mainImage: {
asset: {
url: string;
};
};
slug: {
current: string;
};
body: [object];
}
export interface Comment {
approved: boolean;
comment: string;
email: string;
name: string;
post: {
_ref: string;
_type: string;
};
_createdAt: string;
_id: string;
_rev: string;
_type: string;
_updatedAt: string;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您拥有
接口发布
和函数post()
。我假设您想要接口道具中的前者
,但是编译器和JS引擎会渗透后者。重命名其中一个,以相同名称命名不同的事物很少是一个好主意。
You have
interface Post
andfunction Post()
. I'm assuming you want the former ininterface Props
, but the compiler, and the JS engine, infers the latter.Rename one of them, naming different things with the same name is rarely a good idea anyway.