这是我的第一篇文章!
我正在使用graphQL过滤从Contentful获取的产品列表,以找到与用户单击的产品相匹配的产品。在我将组件转换为Typescript之前,一切都正常。我对TS有点熟悉,几个月前才开始使用它。
当我记录产品时,我会返回具有正确过滤数据的对象,然而,当我访问密钥名称"时;imagesCollection";我收到以下TS错误消息:
类型"{}"上不存在属性"imagesCollection"。ts(2339(
如果I// @ts-ignore
,则产品图像渲染没有问题。这是某种种族状况吗?
打字错误屏幕截图
任何帮助都是非常感谢的,因为我花了大量的时间试图自己解决它。非常感谢。
组件:
const Product = (props: any) => {
// Custom HOOK for fetching Contentful Data
const slug = props.match.params.slug;
const { product } = useContentful(query, slug);
console.log(product);
const [jacketColor, setJacketColor] = useState(null);
const [color, setColor] = useState(null);
useEffect(() => {
setJacketColor(
product.imagesCollection && product.imagesCollection.items[1].url
);
setColor(
// @ts-ignore
product.imagesCollection && product.imagesCollection.items[1].description
);
}, [product]);
const changeColor = (jacketColor: string) => {
// @ts-ignore
const filterHero = product.imagesCollection.items
.filter((heroJacket: { title: string }) =>
heroJacket.title.includes("hero")
)
.filter(
(item: { description: string }) => item.description === jacketColor
);
setJacketColor(filterHero[0].url);
setColor(filterHero[0].description);
};
const thumbnailImages = () => {
return (
// @ts-ignore
product.imagesCollection &&
// @ts-ignore
product.imagesCollection.items
.filter((jacket: queryProps) => jacket.title.includes("thumbnail"))
.map((jacket: { url: string; description: string }, index: number) => {
return (
<img
className={styles.thumbnailImages}
key={`products-${index}`}
src={jacket.url}
// @ts-ignore
alt={product.title}
onClick={() => changeColor(jacket.description)}
/>
);
})
);
};
return (
<>
<Header />
{!product ? (
<Loading />
) : (
<div className={styles.productsContainer}>
{/* @ts-ignore */}
<p className={styles.title}>{product && product.title}</p>
{documentToReactComponents(
// @ts-ignore
product.description && product.description.json,
RICHTEXT_OPTIONS
)}
{/* @ts-ignore */}
<p className={styles.price}>{`$${product && product.price}`}</p>
{
<img
className={styles.productImage}
// @ts-ignore
src={jacketColor}
// @ts-ignore
alt={product && product.title}
/>
}
<p className={styles.selectColor}>{`Select a colour: ${color}`}</p>
<div className={styles.thumbnailImagesWrapper}>
{thumbnailImages()}
</div>
</div>
)}
</>
);
};
export default Product;
获取数据的自定义挂钩:
function useContentful(query: string, slug: string | null) {
const [products, setProducts] = useState([]);
const [product, setProduct] = useState({});
useEffect(() => {
fetch(graphqlURL, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${REACT_APP_CDA_TOKEN}`,
},
body: JSON.stringify({ query }),
})
.then((res) => res.json())
.then(({ data }) => {
if (slug) {
data.arcteryxCollection.items.filter((item: queryProps) => {
return item.slug === slug && setProduct(item);
});
} else {
setProducts(data.arcteryxCollection.items);
}
})
.catch((err) => console.error(err));
}, [query, slug]);
return { product, products };
}
graphQL查询结构:
export const query = `
query {
arcteryxCollection {
items {
title
slug
description {
json
}
price
imagesCollection {
items {
url
title
description
}
}
}
}
}
`;
我正在导入的TS接口:
export interface queryProps {
title: string;
slug: string;
price: number;
description: {
json: {
content: {
value: string;
}[];
};
};
imagesCollection: {
items: {
url: string;
title: string;
description: string;
}[];
};
}
回购链接:https://github.com/danlubbers/arcteryx-graphql
这是因为您正在用一个空对象初始化产品状态。
const [product, setProduct] = useState({});
这使得TypeScript推断出您的状态的类型是一个空对象。因此,它上面没有imagesCollection
您可以为它指定一个类型,也可以使用具有所需属性的对象对其进行初始化。
下面是一个为您的产品添加类型的示例。您可以从Graph QL响应中添加需要使用的其他属性。
type ImageCollectionItem = {
url: string;
title: string;
description: string;
}
type ProductState = {
imagesCollection?: {
items: ImageCollectionItem[]
}
}
//...
const [product, setProduct] = useState<ProductState>({});
这是我发现的最终对我有效的解决方案。在use-contentful.ts钩子中,我改变了过滤响应的方式,将数据存储为数组而不是对象。
此处显示:
const [product, setProduct] = useState<queryProps[]>([]);
let filteredProduct = data.arcteryxCollection.items.filter((item: queryProps) => {
return item.slug === slug;
});
setProduct(filteredProduct);
这使我能够访问产品组件中的数据,并以这种方式呈现:
const { product } = useContentful(query, slug);
const productObj = product[0];
const [jacketColor, setJacketColor] = useState("");
setJacketColor(productObj && productObj.imagesCollection.items[1].url);